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