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