Merge branch 'master' into windows
[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         }
616
617         lxvst_discover_from_path (lxvst_path);
618 }
619
620 int
621 PluginManager::add_lxvst_directory (string path)
622 {
623         if (lxvst_discover_from_path (path) == 0) {
624                 lxvst_path += ':';
625                 lxvst_path += path;
626                 return 0;
627         }
628         return -1;
629 }
630
631 static bool lxvst_filter (const string& str, void *)
632 {
633         /* Not a dotfile, has a prefix before a period, suffix is "so" */
634
635         return str[0] != '.' && (str.length() > 3 && str.find (".so") == (str.length() - 3));
636 }
637
638 int
639 PluginManager::lxvst_discover_from_path (string path)
640 {
641         PathScanner scanner;
642         vector<string *> *plugin_objects;
643         vector<string *>::iterator x;
644         int ret = 0;
645
646         DEBUG_TRACE (DEBUG::PluginManager, string_compose ("Discovering linuxVST plugins along %1\n", path));
647
648         plugin_objects = scanner (lxvst_path, lxvst_filter, 0, false, true);
649
650         if (plugin_objects) {
651                 for (x = plugin_objects->begin(); x != plugin_objects->end (); ++x) {
652                         lxvst_discover (**x);
653                 }
654
655                 vector_delete (plugin_objects);
656         }
657
658         return ret;
659 }
660
661 int
662 PluginManager::lxvst_discover (string path)
663 {
664         VSTInfo* finfo;
665         char buf[32];
666
667         DEBUG_TRACE (DEBUG::PluginManager, string_compose ("checking apparent LXVST plugin at %1\n", path));
668
669         if ((finfo = vstfx_get_info (const_cast<char *> (path.c_str()))) == 0) {
670                 return -1;
671         }
672
673         if (!finfo->canProcessReplacing) {
674                 warning << string_compose (_("linuxVST plugin %1 does not support processReplacing, and so cannot be used in %2 at this time"),
675                                            finfo->name, PROGRAM_NAME)
676                         << endl;
677         }
678
679         PluginInfoPtr info(new LXVSTPluginInfo);
680
681         if (!strcasecmp ("The Unnamed plugin", finfo->name)) {
682                 info->name = PBD::basename_nosuffix (path);
683         } else {
684                 info->name = finfo->name;
685         }
686
687         
688         snprintf (buf, sizeof (buf), "%d", finfo->UniqueID);
689         info->unique_id = buf;
690         info->category = "linuxVSTs";
691         info->path = path;
692         info->creator = finfo->creator;
693         info->index = 0;
694         info->n_inputs.set_audio (finfo->numInputs);
695         info->n_outputs.set_audio (finfo->numOutputs);
696         info->n_inputs.set_midi (finfo->wantMidi ? 1 : 0);
697         info->type = ARDOUR::LXVST;
698
699         /* Make sure we don't find the same plugin in more than one place along
700            the LXVST_PATH We can't use a simple 'find' because the path is included
701            in the PluginInfo, and that is the one thing we can be sure MUST be
702            different if a duplicate instance is found.  So we just compare the type
703            and unique ID (which for some VSTs isn't actually unique...)
704         */
705         
706         if (!_lxvst_plugin_info->empty()) {
707                 for (PluginInfoList::iterator i =_lxvst_plugin_info->begin(); i != _lxvst_plugin_info->end(); ++i) {
708                         if ((info->type == (*i)->type)&&(info->unique_id == (*i)->unique_id)) {
709                                 warning << "Ignoring duplicate Linux VST plugin " << info->name << "\n";
710                                 vstfx_free_info(finfo);
711                                 return 0;
712                         }
713                 }
714         }
715         
716         _lxvst_plugin_info->push_back (info);
717         vstfx_free_info (finfo);
718
719         return 0;
720 }
721
722 #endif // LXVST_SUPPORT
723
724
725 PluginManager::PluginStatusType
726 PluginManager::get_status (const PluginInfoPtr& pi)
727 {
728         PluginStatus ps (pi->type, pi->unique_id);
729         PluginStatusList::const_iterator i =  find (statuses.begin(), statuses.end(), ps);
730         if (i ==  statuses.end() ) {
731                 return Normal;
732         } else {
733                 return i->status;
734         }
735 }
736
737 void
738 PluginManager::save_statuses ()
739 {
740         ofstream ofs;
741         std::string path = Glib::build_filename (user_config_directory(), "plugin_statuses");
742
743         ofs.open (path.c_str(), ios_base::openmode (ios::out|ios::trunc));
744
745         if (!ofs) {
746                 return;
747         }
748
749         for (PluginStatusList::iterator i = statuses.begin(); i != statuses.end(); ++i) {
750                 switch ((*i).type) {
751                 case LADSPA:
752                         ofs << "LADSPA";
753                         break;
754                 case AudioUnit:
755                         ofs << "AudioUnit";
756                         break;
757                 case LV2:
758                         ofs << "LV2";
759                         break;
760                 case Windows_VST:
761                         ofs << "Windows-VST";
762                         break;
763                 case LXVST:
764                         ofs << "LXVST";
765                         break;
766                 }
767
768                 ofs << ' ';
769
770                 switch ((*i).status) {
771                 case Normal:
772                         ofs << "Normal";
773                         break;
774                 case Favorite:
775                         ofs << "Favorite";
776                         break;
777                 case Hidden:
778                         ofs << "Hidden";
779                         break;
780                 }
781
782                 ofs << ' ';
783                 ofs << (*i).unique_id;;
784                 ofs << endl;
785         }
786
787         ofs.close ();
788 }
789
790 void
791 PluginManager::load_statuses ()
792 {
793         std::string path = Glib::build_filename (user_config_directory(), "plugin_statuses");
794         ifstream ifs (path.c_str());
795
796         if (!ifs) {
797                 return;
798         }
799
800         std::string stype;
801         std::string sstatus;
802         std::string id;
803         PluginType type;
804         PluginStatusType status;
805         char buf[1024];
806
807         while (ifs) {
808
809                 ifs >> stype;
810                 if (!ifs) {
811                         break;
812
813                 }
814
815                 ifs >> sstatus;
816                 if (!ifs) {
817                         break;
818
819                 }
820
821                 /* rest of the line is the plugin ID */
822
823                 ifs.getline (buf, sizeof (buf), '\n');
824                 if (!ifs) {
825                         break;
826                 }
827
828                 if (sstatus == "Normal") {
829                         status = Normal;
830                 } else if (sstatus == "Favorite") {
831                         status = Favorite;
832                 } else if (sstatus == "Hidden") {
833                         status = Hidden;
834                 } else {
835                         error << string_compose (_("unknown plugin status type \"%1\" - all entries ignored"), sstatus)
836                                   << endmsg;
837                         statuses.clear ();
838                         break;
839                 }
840
841                 if (stype == "LADSPA") {
842                         type = LADSPA;
843                 } else if (stype == "AudioUnit") {
844                         type = AudioUnit;
845                 } else if (stype == "LV2") {
846                         type = LV2;
847                 } else if (stype == "Windows-VST") {
848                         type = Windows_VST;
849                 } else if (stype == "LXVST") {
850                         type = LXVST;
851                 } else {
852                         error << string_compose (_("unknown plugin type \"%1\" - ignored"), stype)
853                               << endmsg;
854                         continue;
855                 }
856
857                 id = buf;
858                 strip_whitespace_edges (id);
859                 set_status (type, id, status);
860         }
861
862         ifs.close ();
863 }
864
865 void
866 PluginManager::set_status (PluginType t, string id, PluginStatusType status)
867 {
868         PluginStatus ps (t, id, status);
869         statuses.erase (ps);
870
871         if (status == Normal) {
872                 return;
873         }
874
875         statuses.insert (ps);
876 }
877
878 ARDOUR::PluginInfoList&
879 PluginManager::windows_vst_plugin_info ()
880 {
881 #ifdef WINDOWS_VST_SUPPORT
882         if (!_windows_vst_plugin_info) {
883                 windows_vst_refresh ();
884         }
885         return *_windows_vst_plugin_info;
886 #else
887         return _empty_plugin_info;
888 #endif
889 }
890
891 ARDOUR::PluginInfoList&
892 PluginManager::lxvst_plugin_info ()
893 {
894 #ifdef LXVST_SUPPORT
895         if (!_lxvst_plugin_info)
896                 lxvst_refresh();
897         return *_lxvst_plugin_info;
898 #else
899         return _empty_plugin_info;
900 #endif
901 }
902
903 ARDOUR::PluginInfoList&
904 PluginManager::ladspa_plugin_info ()
905 {
906         if (!_ladspa_plugin_info)
907                 ladspa_refresh();
908         return *_ladspa_plugin_info;
909 }
910
911 ARDOUR::PluginInfoList&
912 PluginManager::lv2_plugin_info ()
913 {
914 #ifdef LV2_SUPPORT
915         if (!_lv2_plugin_info)
916                 lv2_refresh();
917         return *_lv2_plugin_info;
918 #else
919         return _empty_plugin_info;
920 #endif
921 }
922
923 ARDOUR::PluginInfoList&
924 PluginManager::au_plugin_info ()
925 {
926 #ifdef AUDIOUNIT_SUPPORT
927         if (!_au_plugin_info)
928                 au_refresh();
929         return *_au_plugin_info;
930 #else
931         return _empty_plugin_info;
932 #endif
933 }