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