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