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