Merge branch 'windows' of git.ardour.org:ardour/ardour into windows
[ardour.git] / libs / ardour / plugin_manager.cc
1 /*
2     Copyright (C) 2000-2006 Paul Davis
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 #ifdef WAF_BUILD
21 #include "libardour-config.h"
22 #endif
23
24 #include <stdint.h>
25
26 #include <sys/types.h>
27 #include <cstdio>
28 #include <cstdlib>
29 #include <fstream>
30
31 #ifdef HAVE_LRDF
32 #include <lrdf.h>
33 #endif
34
35 #ifdef WINDOWS_VST_SUPPORT
36 #include "fst.h"
37 #include "pbd/basename.h"
38 #include <cstring>
39 #endif // WINDOWS_VST_SUPPORT
40
41 #ifdef LXVST_SUPPORT
42 #include "ardour/linux_vst_support.h"
43 #include "pbd/basename.h"
44 #include <cstring>
45 #endif //LXVST_SUPPORT
46
47 #include <glibmm/miscutils.h>
48 #include <glibmm/pattern.h>
49
50 #include "pbd/pathscanner.h"
51 #include "pbd/whitespace.h"
52 #include "pbd/file_utils.h"
53
54 #include "ardour/debug.h"
55 #include "ardour/filesystem_paths.h"
56 #include "ardour/ladspa.h"
57 #include "ardour/ladspa_plugin.h"
58 #include "ardour/plugin.h"
59 #include "ardour/plugin_manager.h"
60 #include "ardour/rc_configuration.h"
61
62 #ifdef SearchPath
63 #undef SearchPath
64 #endif
65
66 #include "ardour/ladspa_search_path.h"
67
68 #ifdef LV2_SUPPORT
69 #include "ardour/lv2_plugin.h"
70 #endif
71
72 #ifdef WINDOWS_VST_SUPPORT
73 #include "ardour/windows_vst_plugin.h"
74 #endif
75
76 #ifdef LXVST_SUPPORT
77 #include "ardour/lxvst_plugin.h"
78 #endif
79
80 #ifdef AUDIOUNIT_SUPPORT
81 #include "ardour/audio_unit.h"
82 #include <Carbon/Carbon.h>
83 #endif
84
85 #include "pbd/error.h"
86 #include "pbd/stl_delete.h"
87
88 #include "i18n.h"
89
90 #include "ardour/debug.h"
91
92 using namespace ARDOUR;
93 using namespace PBD;
94 using namespace std;
95
96 PluginManager* PluginManager::_instance = 0;
97
98 PluginManager&
99 PluginManager::instance() 
100 {
101         if (!_instance) {
102                 _instance = new PluginManager;
103         }
104         return *_instance;
105 }
106
107 PluginManager::PluginManager ()
108         : _windows_vst_plugin_info(0)
109         , _lxvst_plugin_info(0)
110         , _ladspa_plugin_info(0)
111         , _lv2_plugin_info(0)
112         , _au_plugin_info(0)
113 {
114         char* s;
115         string lrdf_path;
116
117         load_statuses ();
118
119         if ((s = getenv ("LADSPA_RDF_PATH"))){
120                 lrdf_path = s;
121         }
122
123         if (lrdf_path.length() == 0) {
124                 lrdf_path = "/usr/local/share/ladspa/rdf:/usr/share/ladspa/rdf";
125         }
126
127         add_lrdf_data(lrdf_path);
128         add_ladspa_presets();
129 #ifdef WINDOWS_VST_SUPPORT
130         if (Config->get_use_windows_vst ()) {
131                 add_windows_vst_presets ();
132         }
133 #endif /* WINDOWS_VST_SUPPORT */
134
135 #ifdef LXVST_SUPPORT
136         if (Config->get_use_lxvst()) {
137                 add_lxvst_presets();
138         }
139 #endif /* Native LinuxVST support*/
140
141         if ((s = getenv ("VST_PATH"))) {
142                 windows_vst_path = s;
143         } else if ((s = getenv ("VST_PLUGINS"))) {
144                 windows_vst_path = s;
145         }
146
147         if ((s = getenv ("LXVST_PATH"))) {
148                 lxvst_path = s;
149         } else if ((s = getenv ("LXVST_PLUGINS"))) {
150                 lxvst_path = s;
151         }
152
153         if (_instance == 0) {
154                 _instance = this;
155         }
156
157         /* the plugin manager is constructed too early to use Profile */
158
159         if (getenv ("ARDOUR_SAE")) {
160                 ladspa_plugin_whitelist.push_back (1203); // single band parametric
161                 ladspa_plugin_whitelist.push_back (1772); // caps compressor
162                 ladspa_plugin_whitelist.push_back (1913); // fast lookahead limiter
163                 ladspa_plugin_whitelist.push_back (1075); // simple RMS expander
164                 ladspa_plugin_whitelist.push_back (1061); // feedback delay line (max 5s)
165                 ladspa_plugin_whitelist.push_back (1216); // gverb
166                 ladspa_plugin_whitelist.push_back (2150); // tap pitch shifter
167         }
168
169         BootMessage (_("Discovering Plugins"));
170 }
171
172
173 PluginManager::~PluginManager()
174 {
175 }
176
177
178 void
179 PluginManager::refresh ()
180 {
181         DEBUG_TRACE (DEBUG::PluginManager, "PluginManager::refresh\n");
182
183         ladspa_refresh ();
184 #ifdef LV2_SUPPORT
185         lv2_refresh ();
186 #endif
187 #ifdef WINDOWS_VST_SUPPORT
188         if (Config->get_use_windows_vst()) {
189                 windows_vst_refresh ();
190         }
191 #endif // WINDOWS_VST_SUPPORT
192
193 #ifdef LXVST_SUPPORT
194         if(Config->get_use_lxvst()) {
195                 lxvst_refresh();
196         }
197 #endif //Native linuxVST SUPPORT
198
199 #ifdef AUDIOUNIT_SUPPORT
200         au_refresh ();
201 #endif
202
203         PluginListChanged (); /* EMIT SIGNAL */
204 }
205
206 void
207 PluginManager::ladspa_refresh ()
208 {
209         if (_ladspa_plugin_info) {
210                 _ladspa_plugin_info->clear ();
211         } else {
212                 _ladspa_plugin_info = new ARDOUR::PluginInfoList ();
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         vector<string> ladspa_modules;
222
223         DEBUG_TRACE (DEBUG::PluginManager, string_compose ("LADSPA: search along: [%1]\n", ladspa_search_path().to_string()));
224
225         Glib::PatternSpec so_extension_pattern("*.so");
226         Glib::PatternSpec dylib_extension_pattern("*.dylib");
227         Glib::PatternSpec dll_extension_pattern("*.dll");
228
229         find_matching_files_in_search_path (ladspa_search_path (),
230                                             so_extension_pattern, ladspa_modules);
231
232         find_matching_files_in_search_path (ladspa_search_path (),
233                                             dylib_extension_pattern, ladspa_modules);
234  
235         find_matching_files_in_search_path (ladspa_search_path (),
236                                             dll_extension_pattern, ladspa_modules);
237
238         for (vector<std::string>::iterator i = ladspa_modules.begin(); i != ladspa_modules.end(); ++i) {
239                 ladspa_discover (*i);
240         }
241 }
242
243 static bool rdf_filter (const string &str, void* /*arg*/)
244 {
245         return str[0] != '.' &&
246                    ((str.find(".rdf")  == (str.length() - 4)) ||
247             (str.find(".rdfs") == (str.length() - 5)) ||
248                     (str.find(".n3")   == (str.length() - 3)) ||
249                     (str.find(".ttl")  == (str.length() - 4)));
250 }
251
252 void
253 PluginManager::add_ladspa_presets()
254 {
255         add_presets ("ladspa");
256 }
257
258 void
259 PluginManager::add_windows_vst_presets()
260 {
261         add_presets ("windows-vst");
262 }
263
264 void
265 PluginManager::add_lxvst_presets()
266 {
267         add_presets ("lxvst");
268 }
269
270 void
271 PluginManager::add_presets(string domain)
272 {
273 #ifdef HAVE_LRDF
274         PathScanner scanner;
275         vector<string *> *presets;
276         vector<string *>::iterator x;
277
278         char* envvar;
279         if ((envvar = getenv ("HOME")) == 0) {
280                 return;
281         }
282
283         string path = string_compose("%1/.%2/rdf", envvar, domain);
284         presets = scanner (path, rdf_filter, 0, false, true);
285
286         if (presets) {
287                 for (x = presets->begin(); x != presets->end (); ++x) {
288                         string file = "file:" + **x;
289                         if (lrdf_read_file(file.c_str())) {
290                                 warning << string_compose(_("Could not parse rdf file: %1"), *x) << endmsg;
291                         }
292                 }
293                 
294                 vector_delete (presets);
295         }
296 #endif
297 }
298
299 void
300 PluginManager::add_lrdf_data (const string &path)
301 {
302 #ifdef HAVE_LRDF
303         PathScanner scanner;
304         vector<string *>* rdf_files;
305         vector<string *>::iterator x;
306
307         rdf_files = scanner (path, rdf_filter, 0, false, true);
308
309         if (rdf_files) {
310                 for (x = rdf_files->begin(); x != rdf_files->end (); ++x) {
311                         const string uri(string("file://") + **x);
312
313                         if (lrdf_read_file(uri.c_str())) {
314                                 warning << "Could not parse rdf file: " << uri << endmsg;
315                         }
316                 }
317
318                 vector_delete (rdf_files);
319         }
320 #endif
321 }
322
323 int
324 PluginManager::ladspa_discover (string path)
325 {
326         DEBUG_TRACE (DEBUG::PluginManager, string_compose ("Checking for LADSPA plugin at %1\n", path));
327
328         Glib::Module module(path);
329         const LADSPA_Descriptor *descriptor;
330         LADSPA_Descriptor_Function dfunc;
331         void* func = 0;
332
333         if (!module) {
334                 error << string_compose(_("LADSPA: cannot load module \"%1\" (%2)"),
335                         path, Glib::Module::get_last_error()) << endmsg;
336                 return -1;
337         }
338
339
340         if (!module.get_symbol("ladspa_descriptor", func)) {
341                 error << string_compose(_("LADSPA: module \"%1\" has no descriptor function."), path) << endmsg;
342                 error << Glib::Module::get_last_error() << endmsg;
343                 return -1;
344         }
345
346         dfunc = (LADSPA_Descriptor_Function)func;
347
348         DEBUG_TRACE (DEBUG::PluginManager, string_compose ("LADSPA plugin found at %1\n", path));
349
350         for (uint32_t i = 0; ; ++i) {
351                 if ((descriptor = dfunc (i)) == 0) {
352                         break;
353                 }
354
355                 if (!ladspa_plugin_whitelist.empty()) {
356                         if (find (ladspa_plugin_whitelist.begin(), ladspa_plugin_whitelist.end(), descriptor->UniqueID) == ladspa_plugin_whitelist.end()) {
357                                 continue;
358                         }
359                 }
360
361                 PluginInfoPtr info(new LadspaPluginInfo);
362                 info->name = descriptor->Name;
363                 info->category = get_ladspa_category(descriptor->UniqueID);
364                 info->creator = descriptor->Maker;
365                 info->path = path;
366                 info->index = i;
367                 info->n_inputs = ChanCount();
368                 info->n_outputs = ChanCount();
369                 info->type = ARDOUR::LADSPA;
370
371                 char buf[32];
372                 snprintf (buf, sizeof (buf), "%lu", descriptor->UniqueID);
373                 info->unique_id = buf;
374
375                 for (uint32_t n=0; n < descriptor->PortCount; ++n) {
376                         if ( LADSPA_IS_PORT_AUDIO (descriptor->PortDescriptors[n]) ) {
377                                 if ( LADSPA_IS_PORT_INPUT (descriptor->PortDescriptors[n]) ) {
378                                         info->n_inputs.set_audio(info->n_inputs.n_audio() + 1);
379                                 }
380                                 else if ( LADSPA_IS_PORT_OUTPUT (descriptor->PortDescriptors[n]) ) {
381                                         info->n_outputs.set_audio(info->n_outputs.n_audio() + 1);
382                                 }
383                         }
384                 }
385
386                 if(_ladspa_plugin_info->empty()){
387                         _ladspa_plugin_info->push_back (info);
388                 }
389
390                 //Ensure that the plugin is not already in the plugin list.
391
392                 bool found = false;
393
394                 for (PluginInfoList::const_iterator i = _ladspa_plugin_info->begin(); i != _ladspa_plugin_info->end(); ++i) {
395                         if(0 == info->unique_id.compare((*i)->unique_id)){
396                               found = true;
397                         }
398                 }
399
400                 if(!found){
401                     _ladspa_plugin_info->push_back (info);
402                 }
403
404                 DEBUG_TRACE (DEBUG::PluginManager, string_compose ("Found LADSPA plugin, name: %1, Inputs: %2, Outputs: %3\n", info->name, info->n_inputs, info->n_outputs));
405         }
406
407 // GDB WILL NOT LIKE YOU IF YOU DO THIS
408 //      dlclose (module);
409
410         return 0;
411 }
412
413 string
414 PluginManager::get_ladspa_category (uint32_t plugin_id)
415 {
416 #ifdef HAVE_LRDF
417         char buf[256];
418         lrdf_statement pattern;
419
420         snprintf(buf, sizeof(buf), "%s%" PRIu32, LADSPA_BASE, plugin_id);
421         pattern.subject = buf;
422         pattern.predicate = const_cast<char*>(RDF_TYPE);
423         pattern.object = 0;
424         pattern.object_type = lrdf_uri;
425
426         lrdf_statement* matches1 = lrdf_matches (&pattern);
427
428         if (!matches1) {
429                 return "Unknown";
430         }
431
432         pattern.subject = matches1->object;
433         pattern.predicate = const_cast<char*>(LADSPA_BASE "hasLabel");
434         pattern.object = 0;
435         pattern.object_type = lrdf_literal;
436
437         lrdf_statement* matches2 = lrdf_matches (&pattern);
438         lrdf_free_statements(matches1);
439
440         if (!matches2) {
441                 return ("Unknown");
442         }
443
444         string label = matches2->object;
445         lrdf_free_statements(matches2);
446
447         /* Kludge LADSPA class names to be singular and match LV2 class names.
448            This avoids duplicate plugin menus for every class, which is necessary
449            to make the plugin category menu at all usable, but is obviously a
450            filthy kludge.
451
452            In the short term, lrdf could be updated so the labels match and a new
453            release made. To support both specs, we should probably be mapping the
454            URIs to the same category in code and perhaps tweaking that hierarchy
455            dynamically to suit the user. Personally, I (drobilla) think that time
456            is better spent replacing the little-used LRDF.
457
458            In the longer term, we will abandon LRDF entirely in favour of LV2 and
459            use that class hierarchy. Aside from fixing this problem properly, that
460            will also allow for translated labels. SWH plugins have been LV2 for
461            ages; TAP needs porting. I don't know of anything else with LRDF data.
462         */
463         if (label == "Utilities") {
464                 return "Utility";
465         } else if (label == "Pitch shifters") {
466                 return "Pitch Shifter";
467         } else if (label != "Dynamics" && label != "Chorus"
468                    &&label[label.length() - 1] == 's'
469                    && label[label.length() - 2] != 's') {
470                 return label.substr(0, label.length() - 1);
471         } else {
472                 return label;
473         }
474 #else
475                 return ("Unknown");
476 #endif
477 }
478
479 #ifdef LV2_SUPPORT
480 void
481 PluginManager::lv2_refresh ()
482 {
483         DEBUG_TRACE (DEBUG::PluginManager, "LV2: refresh\n");
484         delete _lv2_plugin_info;
485         _lv2_plugin_info = LV2PluginInfo::discover();
486 }
487 #endif
488
489 #ifdef AUDIOUNIT_SUPPORT
490 void
491 PluginManager::au_refresh ()
492 {
493         DEBUG_TRACE (DEBUG::PluginManager, "AU: refresh\n");
494         delete _au_plugin_info;
495         _au_plugin_info = AUPluginInfo::discover();
496 }
497
498 #endif
499
500 #ifdef WINDOWS_VST_SUPPORT
501
502 void
503 PluginManager::windows_vst_refresh ()
504 {
505         if (_windows_vst_plugin_info) {
506                 _windows_vst_plugin_info->clear ();
507         } else {
508                 _windows_vst_plugin_info = new ARDOUR::PluginInfoList();
509         }
510
511         if (windows_vst_path.length() == 0) {
512                 windows_vst_path = "/usr/local/lib/vst:/usr/lib/vst";
513         }
514
515         windows_vst_discover_from_path (windows_vst_path);
516 }
517
518 int
519 PluginManager::add_windows_vst_directory (string path)
520 {
521         if (windows_vst_discover_from_path (path) == 0) {
522                 windows_vst_path += ':';
523                 windows_vst_path += path;
524                 return 0;
525         }
526         return -1;
527 }
528
529 static bool windows_vst_filter (const string& str, void *arg)
530 {
531         /* Not a dotfile, has a prefix before a period, suffix is "dll" */
532
533         return str[0] != '.' && (str.length() > 4 && str.find (".dll") == (str.length() - 4));
534 }
535
536 int
537 PluginManager::windows_vst_discover_from_path (string path)
538 {
539         PathScanner scanner;
540         vector<string *> *plugin_objects;
541         vector<string *>::iterator x;
542         int ret = 0;
543
544         DEBUG_TRACE (DEBUG::PluginManager, string_compose ("detecting Windows VST plugins along %1\n", path));
545
546         plugin_objects = scanner (windows_vst_path, windows_vst_filter, 0, false, true);
547
548         if (plugin_objects) {
549                 for (x = plugin_objects->begin(); x != plugin_objects->end (); ++x) {
550                         windows_vst_discover (**x);
551                 }
552
553                 vector_delete (plugin_objects);
554         }
555
556         return ret;
557 }
558
559 int
560 PluginManager::windows_vst_discover (string path)
561 {
562         VSTInfo* finfo;
563         char buf[32];
564
565         if ((finfo = fst_get_info (const_cast<char *> (path.c_str()))) == 0) {
566                 warning << "Cannot get Windows VST information from " << path << endmsg;
567                 return -1;
568         }
569
570         if (!finfo->canProcessReplacing) {
571                 warning << string_compose (_("VST plugin %1 does not support processReplacing, and so cannot be used in %2 at this time"),
572                                            finfo->name, PROGRAM_NAME)
573                         << endl;
574         }
575
576         PluginInfoPtr info (new WindowsVSTPluginInfo);
577
578         /* what a joke freeware VST is */
579
580         if (!strcasecmp ("The Unnamed plugin", finfo->name)) {
581                 info->name = PBD::basename_nosuffix (path);
582         } else {
583                 info->name = finfo->name;
584         }
585
586
587         snprintf (buf, sizeof (buf), "%d", finfo->UniqueID);
588         info->unique_id = buf;
589         info->category = "VST";
590         info->path = path;
591         info->creator = finfo->creator;
592         info->index = 0;
593         info->n_inputs.set_audio (finfo->numInputs);
594         info->n_outputs.set_audio (finfo->numOutputs);
595         info->n_inputs.set_midi (finfo->wantMidi ? 1 : 0);
596         info->type = ARDOUR::Windows_VST;
597
598         _windows_vst_plugin_info->push_back (info);
599         fst_free_info (finfo);
600
601         return 0;
602 }
603
604 #endif // WINDOWS_VST_SUPPORT
605
606 #ifdef LXVST_SUPPORT
607
608 void
609 PluginManager::lxvst_refresh ()
610 {
611         if (_lxvst_plugin_info) {
612                 _lxvst_plugin_info->clear ();
613         } else {
614                 _lxvst_plugin_info = new ARDOUR::PluginInfoList();
615         }
616
617         if (lxvst_path.length() == 0) {
618                 lxvst_path = "/usr/local/lib64/lxvst:/usr/local/lib/lxvst:/usr/lib64/lxvst:/usr/lib/lxvst";
619         }
620
621         lxvst_discover_from_path (lxvst_path);
622 }
623
624 int
625 PluginManager::add_lxvst_directory (string path)
626 {
627         if (lxvst_discover_from_path (path) == 0) {
628                 lxvst_path += ':';
629                 lxvst_path += path;
630                 return 0;
631         }
632         return -1;
633 }
634
635 static bool lxvst_filter (const string& str, void *)
636 {
637         /* Not a dotfile, has a prefix before a period, suffix is "so" */
638
639         return str[0] != '.' && (str.length() > 3 && str.find (".so") == (str.length() - 3));
640 }
641
642 int
643 PluginManager::lxvst_discover_from_path (string path)
644 {
645         PathScanner scanner;
646         vector<string *> *plugin_objects;
647         vector<string *>::iterator x;
648         int ret = 0;
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 }