add -Wpointer-arith -Wcast-qual -Wcast-align and others to compile flags, and fix...
[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
283         vector_delete (plugin_objects);
284         return ret;
285 }
286
287 static bool rdf_filter (const string &str, void* /*arg*/)
288 {
289         return str[0] != '.' &&
290                    ((str.find(".rdf")  == (str.length() - 4)) ||
291             (str.find(".rdfs") == (str.length() - 5)) ||
292                     (str.find(".n3")   == (str.length() - 3)) ||
293                     (str.find(".ttl")  == (str.length() - 4)));
294 }
295
296 void
297 PluginManager::add_ladspa_presets()
298 {
299         add_presets ("ladspa");
300 }
301
302 void
303 PluginManager::add_windows_vst_presets()
304 {
305         add_presets ("windows-vst");
306 }
307
308 void
309 PluginManager::add_lxvst_presets()
310 {
311         add_presets ("lxvst");
312 }
313
314 void
315 PluginManager::add_presets(string domain)
316 {
317
318         PathScanner scanner;
319         vector<string *> *presets;
320         vector<string *>::iterator x;
321
322         char* envvar;
323         if ((envvar = getenv ("HOME")) == 0) {
324                 return;
325         }
326
327         string path = string_compose("%1/.%2/rdf", envvar, domain);
328         presets = scanner (path, rdf_filter, 0, false, true);
329
330         if (presets) {
331                 for (x = presets->begin(); x != presets->end (); ++x) {
332                         string file = "file:" + **x;
333                         if (lrdf_read_file(file.c_str())) {
334                                 warning << string_compose(_("Could not parse rdf file: %1"), *x) << endmsg;
335                         }
336                 }
337         }
338
339         vector_delete (presets);
340 }
341
342 void
343 PluginManager::add_lrdf_data (const string &path)
344 {
345         PathScanner scanner;
346         vector<string *>* rdf_files;
347         vector<string *>::iterator x;
348
349         rdf_files = scanner (path, rdf_filter, 0, false, true);
350
351         if (rdf_files) {
352                 for (x = rdf_files->begin(); x != rdf_files->end (); ++x) {
353                         const string uri(string("file://") + **x);
354
355                         if (lrdf_read_file(uri.c_str())) {
356                                 warning << "Could not parse rdf file: " << uri << endmsg;
357                         }
358                 }
359         }
360
361         vector_delete (rdf_files);
362 }
363
364 int
365 PluginManager::ladspa_discover (string path)
366 {
367         void *module;
368         const LADSPA_Descriptor *descriptor;
369         LADSPA_Descriptor_Function dfunc;
370         const char *errstr;
371
372         if ((module = dlopen (path.c_str(), RTLD_NOW)) == 0) {
373                 error << string_compose(_("LADSPA: cannot load module \"%1\" (%2)"), path, dlerror()) << endmsg;
374                 return -1;
375         }
376
377         dfunc = (LADSPA_Descriptor_Function) dlsym (module, "ladspa_descriptor");
378
379         if ((errstr = dlerror()) != 0) {
380                 error << string_compose(_("LADSPA: module \"%1\" has no descriptor function."), path) << endmsg;
381                 error << errstr << endmsg;
382                 dlclose (module);
383                 return -1;
384         }
385
386         for (uint32_t i = 0; ; ++i) {
387                 if ((descriptor = dfunc (i)) == 0) {
388                         break;
389                 }
390
391                 if (!ladspa_plugin_whitelist.empty()) {
392                         if (find (ladspa_plugin_whitelist.begin(), ladspa_plugin_whitelist.end(), descriptor->UniqueID) == ladspa_plugin_whitelist.end()) {
393                                 continue;
394                         }
395                 }
396
397                 PluginInfoPtr info(new LadspaPluginInfo);
398                 info->name = descriptor->Name;
399                 info->category = get_ladspa_category(descriptor->UniqueID);
400                 info->creator = descriptor->Maker;
401                 info->path = path;
402                 info->index = i;
403                 info->n_inputs = ChanCount();
404                 info->n_outputs = ChanCount();
405                 info->type = ARDOUR::LADSPA;
406
407                 char buf[32];
408                 snprintf (buf, sizeof (buf), "%lu", descriptor->UniqueID);
409                 info->unique_id = buf;
410
411                 for (uint32_t n=0; n < descriptor->PortCount; ++n) {
412                         if ( LADSPA_IS_PORT_AUDIO (descriptor->PortDescriptors[n]) ) {
413                                 if ( LADSPA_IS_PORT_INPUT (descriptor->PortDescriptors[n]) ) {
414                                         info->n_inputs.set_audio(info->n_inputs.n_audio() + 1);
415                                 }
416                                 else if ( LADSPA_IS_PORT_OUTPUT (descriptor->PortDescriptors[n]) ) {
417                                         info->n_outputs.set_audio(info->n_outputs.n_audio() + 1);
418                                 }
419                         }
420                 }
421
422                 if(_ladspa_plugin_info->empty()){
423                         _ladspa_plugin_info->push_back (info);
424                 }
425
426                 //Ensure that the plugin is not already in the plugin list.
427
428                 bool found = false;
429
430                 for (PluginInfoList::const_iterator i = _ladspa_plugin_info->begin(); i != _ladspa_plugin_info->end(); ++i) {
431                         if(0 == info->unique_id.compare((*i)->unique_id)){
432                               found = true;
433                         }
434                 }
435
436                 if(!found){
437                     _ladspa_plugin_info->push_back (info);
438                 }
439         }
440
441 // GDB WILL NOT LIKE YOU IF YOU DO THIS
442 //      dlclose (module);
443
444         return 0;
445 }
446
447 string
448 PluginManager::get_ladspa_category (uint32_t plugin_id)
449 {
450         char buf[256];
451         lrdf_statement pattern;
452
453         snprintf(buf, sizeof(buf), "%s%" PRIu32, LADSPA_BASE, plugin_id);
454         pattern.subject = buf;
455         pattern.predicate = const_cast<char*>(RDF_TYPE);
456         pattern.object = 0;
457         pattern.object_type = lrdf_uri;
458
459         lrdf_statement* matches1 = lrdf_matches (&pattern);
460
461         if (!matches1) {
462                 return "Unknown";
463         }
464
465         pattern.subject = matches1->object;
466         pattern.predicate = const_cast<char*>(LADSPA_BASE "hasLabel");
467         pattern.object = 0;
468         pattern.object_type = lrdf_literal;
469
470         lrdf_statement* matches2 = lrdf_matches (&pattern);
471         lrdf_free_statements(matches1);
472
473         if (!matches2) {
474                 return ("Unknown");
475         }
476
477         string label = matches2->object;
478         lrdf_free_statements(matches2);
479
480         /* Kludge LADSPA class names to be singular and match LV2 class names.
481            This avoids duplicate plugin menus for every class, which is necessary
482            to make the plugin category menu at all usable, but is obviously a
483            filthy kludge.
484
485            In the short term, lrdf could be updated so the labels match and a new
486            release made. To support both specs, we should probably be mapping the
487            URIs to the same category in code and perhaps tweaking that hierarchy
488            dynamically to suit the user. Personally, I (drobilla) think that time
489            is better spent replacing the little-used LRDF.
490
491            In the longer term, we will abandon LRDF entirely in favour of LV2 and
492            use that class hierarchy. Aside from fixing this problem properly, that
493            will also allow for translated labels. SWH plugins have been LV2 for
494            ages; TAP needs porting. I don't know of anything else with LRDF data.
495         */
496         if (label == "Utilities") {
497                 return "Utility";
498         } else if (label == "Pitch shifters") {
499                 return "Pitch Shifter";
500         } else if (label != "Dynamics" && label != "Chorus"
501                    &&label[label.length() - 1] == 's'
502                    && label[label.length() - 2] != 's') {
503                 return label.substr(0, label.length() - 1);
504         } else {
505                 return label;
506         }
507 }
508
509 #ifdef LV2_SUPPORT
510 void
511 PluginManager::lv2_refresh ()
512 {
513         delete _lv2_plugin_info;
514         _lv2_plugin_info = LV2PluginInfo::discover();
515 }
516 #endif
517
518 #ifdef AUDIOUNIT_SUPPORT
519 void
520 PluginManager::au_refresh ()
521 {
522         DEBUG_TRACE (DEBUG::PluginManager, "AU: refresh\n");
523         delete _au_plugin_info;
524         _au_plugin_info = AUPluginInfo::discover();
525 }
526
527 #endif
528
529 #ifdef WINDOWS_VST_SUPPORT
530
531 void
532 PluginManager::windows_vst_refresh ()
533 {
534         if (_windows_vst_plugin_info) {
535                 _windows_vst_plugin_info->clear ();
536         } else {
537                 _windows_vst_plugin_info = new ARDOUR::PluginInfoList();
538         }
539
540         if (windows_vst_path.length() == 0) {
541                 windows_vst_path = "/usr/local/lib/vst:/usr/lib/vst";
542         }
543
544         windows_vst_discover_from_path (windows_vst_path);
545 }
546
547 int
548 PluginManager::add_windows_vst_directory (string path)
549 {
550         if (windows_vst_discover_from_path (path) == 0) {
551                 windows_vst_path += ':';
552                 windows_vst_path += path;
553                 return 0;
554         }
555         return -1;
556 }
557
558 static bool windows_vst_filter (const string& str, void *arg)
559 {
560         /* Not a dotfile, has a prefix before a period, suffix is "dll" */
561
562         return str[0] != '.' && (str.length() > 4 && str.find (".dll") == (str.length() - 4));
563 }
564
565 int
566 PluginManager::windows_vst_discover_from_path (string path)
567 {
568         PathScanner scanner;
569         vector<string *> *plugin_objects;
570         vector<string *>::iterator x;
571         int ret = 0;
572
573         DEBUG_TRACE (DEBUG::PluginManager, string_compose ("detecting Windows VST plugins along %1\n", path));
574
575         plugin_objects = scanner (windows_vst_path, windows_vst_filter, 0, false, true);
576
577         if (plugin_objects) {
578                 for (x = plugin_objects->begin(); x != plugin_objects->end (); ++x) {
579                         windows_vst_discover (**x);
580                 }
581         }
582
583         vector_delete (plugin_objects);
584         return ret;
585 }
586
587 int
588 PluginManager::windows_vst_discover (string path)
589 {
590         VSTInfo* finfo;
591         char buf[32];
592
593         if ((finfo = fst_get_info (const_cast<char *> (path.c_str()))) == 0) {
594                 warning << "Cannot get Windows VST information from " << path << endmsg;
595                 return -1;
596         }
597
598         if (!finfo->canProcessReplacing) {
599                 warning << string_compose (_("VST plugin %1 does not support processReplacing, and so cannot be used in ardour at this time"),
600                                     finfo->name)
601                         << endl;
602         }
603
604         PluginInfoPtr info (new WindowsVSTPluginInfo);
605
606         /* what a joke freeware VST is */
607
608         if (!strcasecmp ("The Unnamed plugin", finfo->name)) {
609                 info->name = PBD::basename_nosuffix (path);
610         } else {
611                 info->name = finfo->name;
612         }
613
614
615         snprintf (buf, sizeof (buf), "%d", finfo->UniqueID);
616         info->unique_id = buf;
617         info->category = "VST";
618         info->path = path;
619         info->creator = finfo->creator;
620         info->index = 0;
621         info->n_inputs.set_audio (finfo->numInputs);
622         info->n_outputs.set_audio (finfo->numOutputs);
623         info->n_inputs.set_midi (finfo->wantMidi ? 1 : 0);
624         info->type = ARDOUR::Windows_VST;
625
626         _windows_vst_plugin_info->push_back (info);
627         fst_free_info (finfo);
628
629         return 0;
630 }
631
632 #endif // WINDOWS_VST_SUPPORT
633
634 #ifdef LXVST_SUPPORT
635
636 void
637 PluginManager::lxvst_refresh ()
638 {
639         if (_lxvst_plugin_info) {
640                 _lxvst_plugin_info->clear ();
641         } else {
642                 _lxvst_plugin_info = new ARDOUR::PluginInfoList();
643         }
644
645         if (lxvst_path.length() == 0) {
646                 lxvst_path = "/usr/local/lib64/lxvst:/usr/local/lib/lxvst:/usr/lib64/lxvst:/usr/lib/lxvst";
647         }
648
649         lxvst_discover_from_path (lxvst_path);
650 }
651
652 int
653 PluginManager::add_lxvst_directory (string path)
654 {
655         if (lxvst_discover_from_path (path) == 0) {
656                 lxvst_path += ':';
657                 lxvst_path += path;
658                 return 0;
659         }
660         return -1;
661 }
662
663 static bool lxvst_filter (const string& str, void *)
664 {
665         /* Not a dotfile, has a prefix before a period, suffix is "so" */
666
667         return str[0] != '.' && (str.length() > 3 && str.find (".so") == (str.length() - 3));
668 }
669
670 int
671 PluginManager::lxvst_discover_from_path (string path)
672 {
673         PathScanner scanner;
674         vector<string *> *plugin_objects;
675         vector<string *>::iterator x;
676         int ret = 0;
677
678         DEBUG_TRACE (DEBUG::PluginManager, string_compose ("Discovering linuxVST plugins along %1\n", path));
679
680         plugin_objects = scanner (lxvst_path, lxvst_filter, 0, false, true);
681
682         if (plugin_objects) {
683                 for (x = plugin_objects->begin(); x != plugin_objects->end (); ++x) {
684                         lxvst_discover (**x);
685                 }
686         }
687
688         vector_delete (plugin_objects);
689         return ret;
690 }
691
692 int
693 PluginManager::lxvst_discover (string path)
694 {
695         VSTInfo* finfo;
696         char buf[32];
697
698         if ((finfo = vstfx_get_info (const_cast<char *> (path.c_str()))) == 0) {
699                 return -1;
700         }
701
702         if (!finfo->canProcessReplacing) {
703                 warning << string_compose (_("linuxVST plugin %1 does not support processReplacing, and so cannot be used in ardour at this time"),
704                                     finfo->name)
705                         << endl;
706         }
707
708         PluginInfoPtr info(new LXVSTPluginInfo);
709
710         if (!strcasecmp ("The Unnamed plugin", finfo->name)) {
711                 info->name = PBD::basename_nosuffix (path);
712         } else {
713                 info->name = finfo->name;
714         }
715
716         
717         snprintf (buf, sizeof (buf), "%d", finfo->UniqueID);
718         info->unique_id = buf;
719         info->category = "linuxVSTs";
720         info->path = path;
721         info->creator = finfo->creator;
722         info->index = 0;
723         info->n_inputs.set_audio (finfo->numInputs);
724         info->n_outputs.set_audio (finfo->numOutputs);
725         info->n_inputs.set_midi (finfo->wantMidi ? 1 : 0);
726         info->type = ARDOUR::LXVST;
727
728         /* Make sure we don't find the same plugin in more than one place along
729            the LXVST_PATH We can't use a simple 'find' because the path is included
730            in the PluginInfo, and that is the one thing we can be sure MUST be
731            different if a duplicate instance is found.  So we just compare the type
732            and unique ID (which for some VSTs isn't actually unique...)
733         */
734         
735         if (!_lxvst_plugin_info->empty()) {
736                 for (PluginInfoList::iterator i =_lxvst_plugin_info->begin(); i != _lxvst_plugin_info->end(); ++i) {
737                         if ((info->type == (*i)->type)&&(info->unique_id == (*i)->unique_id)) {
738                                 warning << "Ignoring duplicate Linux VST plugin " << info->name << "\n";
739                                 vstfx_free_info(finfo);
740                                 return 0;
741                         }
742                 }
743         }
744         
745         _lxvst_plugin_info->push_back (info);
746         vstfx_free_info (finfo);
747
748         return 0;
749 }
750
751 #endif // LXVST_SUPPORT
752
753
754 PluginManager::PluginStatusType
755 PluginManager::get_status (const PluginInfoPtr& pi)
756 {
757         PluginStatus ps (pi->type, pi->unique_id);
758         PluginStatusList::const_iterator i =  find (statuses.begin(), statuses.end(), ps);
759         if (i ==  statuses.end() ) {
760                 return Normal;
761         } else {
762                 return i->status;
763         }
764 }
765
766 void
767 PluginManager::save_statuses ()
768 {
769         ofstream ofs;
770         std::string path = Glib::build_filename (user_config_directory(), "plugin_statuses");
771
772         ofs.open (path.c_str(), ios_base::openmode (ios::out|ios::trunc));
773
774         if (!ofs) {
775                 return;
776         }
777
778         for (PluginStatusList::iterator i = statuses.begin(); i != statuses.end(); ++i) {
779                 switch ((*i).type) {
780                 case LADSPA:
781                         ofs << "LADSPA";
782                         break;
783                 case AudioUnit:
784                         ofs << "AudioUnit";
785                         break;
786                 case LV2:
787                         ofs << "LV2";
788                         break;
789                 case Windows_VST:
790                         ofs << "Windows-VST";
791                         break;
792                 case LXVST:
793                         ofs << "LXVST";
794                         break;
795                 }
796
797                 ofs << ' ';
798
799                 switch ((*i).status) {
800                 case Normal:
801                         ofs << "Normal";
802                         break;
803                 case Favorite:
804                         ofs << "Favorite";
805                         break;
806                 case Hidden:
807                         ofs << "Hidden";
808                         break;
809                 }
810
811                 ofs << ' ';
812                 ofs << (*i).unique_id;;
813                 ofs << endl;
814         }
815
816         ofs.close ();
817 }
818
819 void
820 PluginManager::load_statuses ()
821 {
822         std::string path = Glib::build_filename (user_config_directory(), "plugin_statuses");
823         ifstream ifs (path.c_str());
824
825         if (!ifs) {
826                 return;
827         }
828
829         std::string stype;
830         std::string sstatus;
831         std::string id;
832         PluginType type;
833         PluginStatusType status;
834         char buf[1024];
835
836         while (ifs) {
837
838                 ifs >> stype;
839                 if (!ifs) {
840                         break;
841
842                 }
843
844                 ifs >> sstatus;
845                 if (!ifs) {
846                         break;
847
848                 }
849
850                 /* rest of the line is the plugin ID */
851
852                 ifs.getline (buf, sizeof (buf), '\n');
853                 if (!ifs) {
854                         break;
855                 }
856
857                 if (sstatus == "Normal") {
858                         status = Normal;
859                 } else if (sstatus == "Favorite") {
860                         status = Favorite;
861                 } else if (sstatus == "Hidden") {
862                         status = Hidden;
863                 } else {
864                         error << string_compose (_("unknown plugin status type \"%1\" - all entries ignored"), sstatus)
865                                   << endmsg;
866                         statuses.clear ();
867                         break;
868                 }
869
870                 if (stype == "LADSPA") {
871                         type = LADSPA;
872                 } else if (stype == "AudioUnit") {
873                         type = AudioUnit;
874                 } else if (stype == "LV2") {
875                         type = LV2;
876                 } else if (stype == "Windows-VST") {
877                         type = Windows_VST;
878                 } else if (stype == "LXVST") {
879                         type = LXVST;
880                 } else {
881                         error << string_compose (_("unknown plugin type \"%1\" - ignored"), stype)
882                               << endmsg;
883                         continue;
884                 }
885
886                 id = buf;
887                 strip_whitespace_edges (id);
888                 set_status (type, id, status);
889         }
890
891         ifs.close ();
892 }
893
894 void
895 PluginManager::set_status (PluginType t, string id, PluginStatusType status)
896 {
897         PluginStatus ps (t, id, status);
898         statuses.erase (ps);
899
900         if (status == Normal) {
901                 return;
902         }
903
904         statuses.insert (ps);
905 }
906
907 ARDOUR::PluginInfoList&
908 PluginManager::windows_vst_plugin_info ()
909 {
910 #ifdef WINDOWS_VST_SUPPORT
911         if (!_windows_vst_plugin_info) {
912                 windows_vst_refresh ();
913         }
914         return *_windows_vst_plugin_info;
915 #else
916         return _empty_plugin_info;
917 #endif
918 }
919
920 ARDOUR::PluginInfoList&
921 PluginManager::lxvst_plugin_info ()
922 {
923 #ifdef LXVST_SUPPORT
924         if (!_lxvst_plugin_info)
925                 lxvst_refresh();
926         return *_lxvst_plugin_info;
927 #else
928         return _empty_plugin_info;
929 #endif
930 }
931
932 ARDOUR::PluginInfoList&
933 PluginManager::ladspa_plugin_info ()
934 {
935         if (!_ladspa_plugin_info)
936                 ladspa_refresh();
937         return *_ladspa_plugin_info;
938 }
939
940 ARDOUR::PluginInfoList&
941 PluginManager::lv2_plugin_info ()
942 {
943 #ifdef LV2_SUPPORT
944         if (!_lv2_plugin_info)
945                 lv2_refresh();
946         return *_lv2_plugin_info;
947 #else
948         return _empty_plugin_info;
949 #endif
950 }
951
952 ARDOUR::PluginInfoList&
953 PluginManager::au_plugin_info ()
954 {
955 #ifdef AUDIOUNIT_SUPPORT
956         if (!_au_plugin_info)
957                 au_refresh();
958         return *_au_plugin_info;
959 #else
960         return _empty_plugin_info;
961 #endif
962 }