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