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