When running an (MSVC built) VST scanner app, make sure we can utilise debuggable...
[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 #if defined WINDOWS_VST_SUPPORT || defined LXVST_SUPPORT
119         PBD::Searchpath vstsp(Glib::build_filename(ARDOUR::ardour_dll_directory(), "fst"));
120 #ifdef PLATFORM_WINDOWS
121         vstsp += Glib::build_filename(g_win32_get_package_installation_directory_of_module (0), "bin");
122 #else
123         vstsp += Glib::getenv("PATH");
124 #endif
125         if (!PBD::find_file (vstsp,
126 #ifdef PLATFORM_WINDOWS
127     #ifdef DEBUGGABLE_SCANNER_APP
128         #if defined(DEBUG) || defined(_DEBUG)
129                                 "ardour-vst-scannerD.exe"
130         #else
131                                 "ardour-vst-scannerRDC.exe"
132         #endif
133     #else
134                                 "ardour-vst-scanner.exe"
135     #endif
136 #else
137                                 "ardour-vst-scanner"
138 #endif
139                                 , scanner_bin_path)) {
140                 PBD::warning << "VST scanner app (ardour-vst-scanner) not found in path " << vstsp.to_string() <<  endmsg;
141         }
142 #endif
143
144         load_statuses ();
145
146         if ((s = getenv ("LADSPA_RDF_PATH"))){
147                 lrdf_path = s;
148         }
149
150         if (lrdf_path.length() == 0) {
151                 lrdf_path = "/usr/local/share/ladspa/rdf:/usr/share/ladspa/rdf";
152         }
153
154         add_lrdf_data(lrdf_path);
155         add_ladspa_presets();
156 #ifdef WINDOWS_VST_SUPPORT
157         if (Config->get_use_windows_vst ()) {
158                 add_windows_vst_presets ();
159         }
160 #endif /* WINDOWS_VST_SUPPORT */
161
162 #ifdef LXVST_SUPPORT
163         if (Config->get_use_lxvst()) {
164                 add_lxvst_presets();
165         }
166 #endif /* Native LinuxVST support*/
167
168         if ((s = getenv ("VST_PATH"))) {
169                 windows_vst_path = s;
170         } else if ((s = getenv ("VST_PLUGINS"))) {
171                 windows_vst_path = s;
172         }
173
174         if (windows_vst_path.length() == 0) {
175                 windows_vst_path = vst_search_path ();
176         }
177
178         if ((s = getenv ("LXVST_PATH"))) {
179                 lxvst_path = s;
180         } else if ((s = getenv ("LXVST_PLUGINS"))) {
181                 lxvst_path = s;
182         }
183
184         if (lxvst_path.length() == 0) {
185                 lxvst_path = "/usr/local/lib64/lxvst:/usr/local/lib/lxvst:/usr/lib64/lxvst:/usr/lib/lxvst:"
186                         "/usr/local/lib64/linux_vst:/usr/local/lib/linux_vst:/usr/lib64/linux_vst:/usr/lib/linux_vst:"
187                         "/usr/lib/vst:/usr/local/lib/vst";
188         }
189
190         /* first time setup, use 'default' path */
191         if (Config->get_plugin_path_lxvst() == X_("@default@")) {
192                 Config->set_plugin_path_lxvst(get_default_lxvst_path());
193         }
194         if (Config->get_plugin_path_vst() == X_("@default@")) {
195                 Config->set_plugin_path_vst(get_default_windows_vst_path());
196         }
197
198         if (_instance == 0) {
199                 _instance = this;
200         }
201
202         BootMessage (_("Discovering Plugins"));
203 }
204
205
206 PluginManager::~PluginManager()
207 {
208         if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) {
209                 // don't bother, just exit quickly.
210                 delete _windows_vst_plugin_info;
211                 delete _lxvst_plugin_info;
212                 delete _ladspa_plugin_info;
213                 delete _lv2_plugin_info;
214                 delete _au_plugin_info;
215         }
216 }
217
218 void
219 PluginManager::refresh (bool cache_only)
220 {
221         DEBUG_TRACE (DEBUG::PluginManager, "PluginManager::refresh\n");
222         _cancel_scan = false;
223
224         BootMessage (_("Scanning LADSPA Plugins"));
225         ladspa_refresh ();
226 #ifdef LV2_SUPPORT
227         BootMessage (_("Scanning LV2 Plugins"));
228         lv2_refresh ();
229 #endif
230 #ifdef WINDOWS_VST_SUPPORT
231         if (Config->get_use_windows_vst()) {
232                 BootMessage (_("Scanning Windows VST Plugins"));
233                 windows_vst_refresh (cache_only);
234         }
235 #endif // WINDOWS_VST_SUPPORT
236
237 #ifdef LXVST_SUPPORT
238         if(Config->get_use_lxvst()) {
239                 BootMessage (_("Scanning Linux VST Plugins"));
240                 lxvst_refresh(cache_only);
241         }
242 #endif //Native linuxVST SUPPORT
243
244 #ifdef AUDIOUNIT_SUPPORT
245         BootMessage (_("Scanning AU Plugins"));
246         au_refresh ();
247 #endif
248
249         BootMessage (_("Plugin Scan Complete..."));
250         PluginListChanged (); /* EMIT SIGNAL */
251         PluginScanMessage(X_("closeme"), "", false);
252         _cancel_scan = false;
253 }
254
255 void
256 PluginManager::cancel_plugin_scan ()
257 {
258         _cancel_scan = true;
259 }
260
261 void
262 PluginManager::cancel_plugin_timeout ()
263 {
264         _cancel_timeout = true;
265 }
266
267 void
268 PluginManager::clear_vst_cache ()
269 {
270         // see also libs/ardour/vst_info_file.cc - vstfx_infofile_path()
271 #ifdef WINDOWS_VST_SUPPORT
272         {
273                 vector<string> fsi_files;
274                 find_files_matching_regex (fsi_files, Config->get_plugin_path_vst(), "\\.fsi$");
275                 for (vector<string>::iterator i = fsi_files.begin(); i != fsi_files.end (); ++i) {
276                         ::g_unlink(i->c_str());
277                 }
278         }
279 #endif
280
281 #ifdef LXVST_SUPPORT
282         {
283                 vector<string> fsi_files;
284                 find_files_matching_regex (fsi_files, Config->get_plugin_path_lxvst(), "\\.fsi$");
285                 for (vector<string>::iterator i = fsi_files.begin(); i != fsi_files.end (); ++i) {
286                         ::g_unlink(i->c_str());
287                 }
288         }
289 #endif
290
291 #if (defined WINDOWS_VST_SUPPORT || defined LXVST_SUPPORT)
292         {
293                 string personal = get_personal_vst_info_cache_dir();
294                 vector<string> fsi_files;
295                 find_files_matching_regex (fsi_files, personal, "\\.fsi$");
296                 for (vector<string>::iterator i = fsi_files.begin(); i != fsi_files.end (); ++i) {
297                         ::g_unlink(i->c_str());
298                 }
299         }
300 #endif
301 }
302
303 void
304 PluginManager::clear_vst_blacklist ()
305 {
306 #ifdef WINDOWS_VST_SUPPORT
307         {
308                 vector<string> fsi_files;
309                 find_files_matching_regex (fsi_files, Config->get_plugin_path_vst(), "\\.fsb$");
310                 for (vector<string>::iterator i = fsi_files.begin(); i != fsi_files.end (); ++i) {
311                         ::g_unlink(i->c_str());
312                 }
313         }
314 #endif
315
316 #ifdef LXVST_SUPPORT
317         {
318                 vector<string> fsi_files;
319                 find_files_matching_regex (fsi_files, Config->get_plugin_path_lxvst(), "\\.fsb$");
320                 for (vector<string>::iterator i = fsi_files.begin(); i != fsi_files.end (); ++i) {
321                         ::g_unlink(i->c_str());
322                 }
323         }
324 #endif
325
326 #if (defined WINDOWS_VST_SUPPORT || defined LXVST_SUPPORT)
327         {
328                 string personal = get_personal_vst_blacklist_dir();
329
330                 vector<string> fsi_files;
331                 find_files_matching_regex (fsi_files, personal, "\\.fsb$");
332                 for (vector<string>::iterator i = fsi_files.begin(); i != fsi_files.end (); ++i) {
333                         ::g_unlink(i->c_str());
334                 }
335         }
336 #endif
337 }
338
339 void
340 PluginManager::ladspa_refresh ()
341 {
342         if (_ladspa_plugin_info) {
343                 _ladspa_plugin_info->clear ();
344         } else {
345                 _ladspa_plugin_info = new ARDOUR::PluginInfoList ();
346         }
347
348         /* allow LADSPA_PATH to augment, not override standard locations */
349
350         /* Only add standard locations to ladspa_path if it doesn't
351          * already contain them. Check for trailing G_DIR_SEPARATOR too.
352          */
353
354         vector<string> ladspa_modules;
355
356         DEBUG_TRACE (DEBUG::PluginManager, string_compose ("LADSPA: search along: [%1]\n", ladspa_search_path().to_string()));
357
358         find_files_matching_pattern (ladspa_modules, ladspa_search_path (), "*.so");
359         find_files_matching_pattern (ladspa_modules, ladspa_search_path (), "*.dylib");
360         find_files_matching_pattern (ladspa_modules, ladspa_search_path (), "*.dll");
361
362         for (vector<std::string>::iterator i = ladspa_modules.begin(); i != ladspa_modules.end(); ++i) {
363                 ARDOUR::PluginScanMessage(_("LADSPA"), *i, false);
364                 ladspa_discover (*i);
365         }
366 }
367
368 static bool rdf_filter (const string &str, void* /*arg*/)
369 {
370         return str[0] != '.' &&
371                    ((str.find(".rdf")  == (str.length() - 4)) ||
372             (str.find(".rdfs") == (str.length() - 5)) ||
373                     (str.find(".n3")   == (str.length() - 3)) ||
374                     (str.find(".ttl")  == (str.length() - 4)));
375 }
376
377 void
378 PluginManager::add_ladspa_presets()
379 {
380         add_presets ("ladspa");
381 }
382
383 void
384 PluginManager::add_windows_vst_presets()
385 {
386         add_presets ("windows-vst");
387 }
388
389 void
390 PluginManager::add_lxvst_presets()
391 {
392         add_presets ("lxvst");
393 }
394
395 void
396 PluginManager::add_presets(string domain)
397 {
398 #ifdef HAVE_LRDF
399         vector<string> presets;
400         vector<string>::iterator x;
401
402         char* envvar;
403         if ((envvar = getenv ("HOME")) == 0) {
404                 return;
405         }
406
407         string path = string_compose("%1/.%2/rdf", envvar, domain);
408         find_files_matching_filter (presets, path, rdf_filter, 0, false, true);
409
410         for (x = presets.begin(); x != presets.end (); ++x) {
411                 string file = "file:" + *x;
412                 if (lrdf_read_file(file.c_str())) {
413                         warning << string_compose(_("Could not parse rdf file: %1"), *x) << endmsg;
414                 }
415         }
416
417 #endif
418 }
419
420 void
421 PluginManager::add_lrdf_data (const string &path)
422 {
423 #ifdef HAVE_LRDF
424         vector<string> rdf_files;
425         vector<string>::iterator x;
426
427         find_files_matching_filter (rdf_files, path, rdf_filter, 0, false, true);
428
429         for (x = rdf_files.begin(); x != rdf_files.end (); ++x) {
430                 const string uri(string("file://") + *x);
431
432                 if (lrdf_read_file(uri.c_str())) {
433                         warning << "Could not parse rdf file: " << uri << endmsg;
434                 }
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         windows_vst_discover_from_path (Config->get_plugin_path_vst(), cache_only);
628 }
629
630 static bool windows_vst_filter (const string& str, void * /*arg*/)
631 {
632         /* Not a dotfile, has a prefix before a period, suffix is "dll" */
633
634         return str[0] != '.' && (str.length() > 4 && str.find (".dll") == (str.length() - 4));
635 }
636
637 int
638 PluginManager::windows_vst_discover_from_path (string path, bool cache_only)
639 {
640         vector<string> plugin_objects;
641         vector<string>::iterator x;
642         int ret = 0;
643
644         DEBUG_TRACE (DEBUG::PluginManager, string_compose ("detecting Windows VST plugins along %1\n", path));
645
646         find_files_matching_filter (plugin_objects, Config->get_plugin_path_vst(), windows_vst_filter, 0, false, true);
647
648         for (x = plugin_objects.begin(); x != plugin_objects.end (); ++x) {
649                 ARDOUR::PluginScanMessage(_("VST"), *x, !cache_only && !cancelled());
650                 windows_vst_discover (*x, cache_only || cancelled());
651         }
652
653         return ret;
654 }
655
656 int
657 PluginManager::windows_vst_discover (string path, bool cache_only)
658 {
659         DEBUG_TRACE (DEBUG::PluginManager, string_compose ("windows_vst_discover '%1'\n", path));
660
661         _cancel_timeout = false;
662         vector<VSTInfo*> * finfos = vstfx_get_info_fst (const_cast<char *> (path.c_str()),
663                         cache_only ? VST_SCAN_CACHE_ONLY : VST_SCAN_USE_APP);
664
665         if (finfos->empty()) {
666                 DEBUG_TRACE (DEBUG::PluginManager, string_compose ("Cannot get Windows VST information from '%1'\n", path));
667                 return -1;
668         }
669
670         uint32_t discovered = 0;
671         for (vector<VSTInfo *>::iterator x = finfos->begin(); x != finfos->end(); ++x) {
672                 VSTInfo* finfo = *x;
673                 char buf[32];
674
675                 if (!finfo->canProcessReplacing) {
676                         warning << string_compose (_("VST plugin %1 does not support processReplacing, and so cannot be used in %2 at this time"),
677                                                          finfo->name, PROGRAM_NAME)
678                                 << endl;
679                         continue;
680                 }
681
682                 PluginInfoPtr info (new WindowsVSTPluginInfo);
683
684                 /* what a joke freeware VST is */
685
686                 if (!strcasecmp ("The Unnamed plugin", finfo->name)) {
687                         info->name = PBD::basename_nosuffix (path);
688                 } else {
689                         info->name = finfo->name;
690                 }
691
692
693                 snprintf (buf, sizeof (buf), "%d", finfo->UniqueID);
694                 info->unique_id = buf;
695                 info->category = "VST";
696                 info->path = path;
697                 info->creator = finfo->creator;
698                 info->index = 0;
699                 info->n_inputs.set_audio (finfo->numInputs);
700                 info->n_outputs.set_audio (finfo->numOutputs);
701                 info->n_inputs.set_midi ((finfo->wantMidi&1) ? 1 : 0);
702                 info->n_outputs.set_midi ((finfo->wantMidi&2) ? 1 : 0);
703                 info->type = ARDOUR::Windows_VST;
704
705                 // TODO: check dup-IDs (lxvst AND windows vst)
706                 bool duplicate = false;
707
708                 if (!_windows_vst_plugin_info->empty()) {
709                         for (PluginInfoList::iterator i =_windows_vst_plugin_info->begin(); i != _windows_vst_plugin_info->end(); ++i) {
710                                 if ((info->type == (*i)->type)&&(info->unique_id == (*i)->unique_id)) {
711                                         warning << "Ignoring duplicate Windows VST plugin " << info->name << "\n";
712                                         duplicate = true;
713                                         break;
714                                 }
715                         }
716                 }
717
718                 if (!duplicate) {
719                         DEBUG_TRACE (DEBUG::PluginManager, string_compose ("Windows VST plugin ID '%1'\n", info->unique_id));
720                         _windows_vst_plugin_info->push_back (info);
721                         discovered++;
722                 }
723         }
724
725         vstfx_free_info_list (finfos);
726         return discovered > 0 ? 0 : -1;
727 }
728
729 #endif // WINDOWS_VST_SUPPORT
730
731 #ifdef LXVST_SUPPORT
732
733 void
734 PluginManager::lxvst_refresh (bool cache_only)
735 {
736         if (_lxvst_plugin_info) {
737                 _lxvst_plugin_info->clear ();
738         } else {
739                 _lxvst_plugin_info = new ARDOUR::PluginInfoList();
740         }
741
742         lxvst_discover_from_path (Config->get_plugin_path_lxvst(), cache_only);
743 }
744
745 static bool lxvst_filter (const string& str, void *)
746 {
747         /* Not a dotfile, has a prefix before a period, suffix is "so" */
748
749         return str[0] != '.' && (str.length() > 3 && str.find (".so") == (str.length() - 3));
750 }
751
752 int
753 PluginManager::lxvst_discover_from_path (string path, bool cache_only)
754 {
755         vector<string> plugin_objects;
756         vector<string>::iterator x;
757         int ret = 0;
758
759 #ifndef NDEBUG
760         (void) path;
761 #endif
762
763         DEBUG_TRACE (DEBUG::PluginManager, string_compose ("Discovering linuxVST plugins along %1\n", path));
764
765         find_files_matching_filter (plugin_objects, Config->get_plugin_path_lxvst(), lxvst_filter, 0, false, true);
766
767         for (x = plugin_objects.begin(); x != plugin_objects.end (); ++x) {
768                 ARDOUR::PluginScanMessage(_("LXVST"), *x, !cache_only && !cancelled());
769                 lxvst_discover (*x, cache_only || cancelled());
770         }
771
772         return ret;
773 }
774
775 int
776 PluginManager::lxvst_discover (string path, bool cache_only)
777 {
778         DEBUG_TRACE (DEBUG::PluginManager, string_compose ("checking apparent LXVST plugin at %1\n", path));
779
780         _cancel_timeout = false;
781         vector<VSTInfo*> * finfos = vstfx_get_info_lx (const_cast<char *> (path.c_str()),
782                         cache_only ? VST_SCAN_CACHE_ONLY : VST_SCAN_USE_APP);
783
784         if (finfos->empty()) {
785                 DEBUG_TRACE (DEBUG::PluginManager, string_compose ("Cannot get Linux VST information from '%1'\n", path));
786                 return -1;
787         }
788
789         uint32_t discovered = 0;
790         for (vector<VSTInfo *>::iterator x = finfos->begin(); x != finfos->end(); ++x) {
791                 VSTInfo* finfo = *x;
792                 char buf[32];
793
794                 if (!finfo->canProcessReplacing) {
795                         warning << string_compose (_("linuxVST plugin %1 does not support processReplacing, and so cannot be used in %2 at this time"),
796                                                          finfo->name, PROGRAM_NAME)
797                                 << endl;
798                         continue;
799                 }
800
801                 PluginInfoPtr info(new LXVSTPluginInfo);
802
803                 if (!strcasecmp ("The Unnamed plugin", finfo->name)) {
804                         info->name = PBD::basename_nosuffix (path);
805                 } else {
806                         info->name = finfo->name;
807                 }
808
809
810                 snprintf (buf, sizeof (buf), "%d", finfo->UniqueID);
811                 info->unique_id = buf;
812                 info->category = "linuxVSTs";
813                 info->path = path;
814                 info->creator = finfo->creator;
815                 info->index = 0;
816                 info->n_inputs.set_audio (finfo->numInputs);
817                 info->n_outputs.set_audio (finfo->numOutputs);
818                 info->n_inputs.set_midi ((finfo->wantMidi&1) ? 1 : 0);
819                 info->n_outputs.set_midi ((finfo->wantMidi&2) ? 1 : 0);
820                 info->type = ARDOUR::LXVST;
821
822                                         /* Make sure we don't find the same plugin in more than one place along
823                          the LXVST_PATH We can't use a simple 'find' because the path is included
824                          in the PluginInfo, and that is the one thing we can be sure MUST be
825                          different if a duplicate instance is found.  So we just compare the type
826                          and unique ID (which for some VSTs isn't actually unique...)
827                 */
828
829                 // TODO: check dup-IDs with windowsVST, too
830                 bool duplicate = false;
831                 if (!_lxvst_plugin_info->empty()) {
832                         for (PluginInfoList::iterator i =_lxvst_plugin_info->begin(); i != _lxvst_plugin_info->end(); ++i) {
833                                 if ((info->type == (*i)->type)&&(info->unique_id == (*i)->unique_id)) {
834                                         warning << "Ignoring duplicate Linux VST plugin " << info->name << "\n";
835                                         duplicate = true;
836                                         break;
837                                 }
838                         }
839                 }
840
841                 if (!duplicate) {
842                         _lxvst_plugin_info->push_back (info);
843                         discovered++;
844                 }
845         }
846
847         vstfx_free_info_list (finfos);
848         return discovered > 0 ? 0 : -1;
849 }
850
851 #endif // LXVST_SUPPORT
852
853
854 PluginManager::PluginStatusType
855 PluginManager::get_status (const PluginInfoPtr& pi)
856 {
857         PluginStatus ps (pi->type, pi->unique_id);
858         PluginStatusList::const_iterator i =  find (statuses.begin(), statuses.end(), ps);
859         if (i ==  statuses.end() ) {
860                 return Normal;
861         } else {
862                 return i->status;
863         }
864 }
865
866 void
867 PluginManager::save_statuses ()
868 {
869         ofstream ofs;
870         std::string path = Glib::build_filename (user_config_directory(), "plugin_statuses");
871
872         ofs.open (path.c_str(), ios_base::openmode (ios::out|ios::trunc));
873
874         if (!ofs) {
875                 return;
876         }
877
878         for (PluginStatusList::iterator i = statuses.begin(); i != statuses.end(); ++i) {
879                 switch ((*i).type) {
880                 case LADSPA:
881                         ofs << "LADSPA";
882                         break;
883                 case AudioUnit:
884                         ofs << "AudioUnit";
885                         break;
886                 case LV2:
887                         ofs << "LV2";
888                         break;
889                 case Windows_VST:
890                         ofs << "Windows-VST";
891                         break;
892                 case LXVST:
893                         ofs << "LXVST";
894                         break;
895                 }
896
897                 ofs << ' ';
898
899                 switch ((*i).status) {
900                 case Normal:
901                         ofs << "Normal";
902                         break;
903                 case Favorite:
904                         ofs << "Favorite";
905                         break;
906                 case Hidden:
907                         ofs << "Hidden";
908                         break;
909                 }
910
911                 ofs << ' ';
912                 ofs << (*i).unique_id;;
913                 ofs << endl;
914         }
915
916         ofs.close ();
917 }
918
919 void
920 PluginManager::load_statuses ()
921 {
922         std::string path = Glib::build_filename (user_config_directory(), "plugin_statuses");
923         ifstream ifs (path.c_str());
924
925         if (!ifs) {
926                 return;
927         }
928
929         std::string stype;
930         std::string sstatus;
931         std::string id;
932         PluginType type;
933         PluginStatusType status;
934         char buf[1024];
935
936         while (ifs) {
937
938                 ifs >> stype;
939                 if (!ifs) {
940                         break;
941
942                 }
943
944                 ifs >> sstatus;
945                 if (!ifs) {
946                         break;
947
948                 }
949
950                 /* rest of the line is the plugin ID */
951
952                 ifs.getline (buf, sizeof (buf), '\n');
953                 if (!ifs) {
954                         break;
955                 }
956
957                 if (sstatus == "Normal") {
958                         status = Normal;
959                 } else if (sstatus == "Favorite") {
960                         status = Favorite;
961                 } else if (sstatus == "Hidden") {
962                         status = Hidden;
963                 } else {
964                         error << string_compose (_("unknown plugin status type \"%1\" - all entries ignored"), sstatus)
965                                   << endmsg;
966                         statuses.clear ();
967                         break;
968                 }
969
970                 if (stype == "LADSPA") {
971                         type = LADSPA;
972                 } else if (stype == "AudioUnit") {
973                         type = AudioUnit;
974                 } else if (stype == "LV2") {
975                         type = LV2;
976                 } else if (stype == "Windows-VST") {
977                         type = Windows_VST;
978                 } else if (stype == "LXVST") {
979                         type = LXVST;
980                 } else {
981                         error << string_compose (_("unknown plugin type \"%1\" - ignored"), stype)
982                               << endmsg;
983                         continue;
984                 }
985
986                 id = buf;
987                 strip_whitespace_edges (id);
988                 set_status (type, id, status);
989         }
990
991         ifs.close ();
992 }
993
994 void
995 PluginManager::set_status (PluginType t, string id, PluginStatusType status)
996 {
997         PluginStatus ps (t, id, status);
998         statuses.erase (ps);
999
1000         if (status == Normal) {
1001                 return;
1002         }
1003
1004         statuses.insert (ps);
1005 }
1006
1007 ARDOUR::PluginInfoList&
1008 PluginManager::windows_vst_plugin_info ()
1009 {
1010 #ifdef WINDOWS_VST_SUPPORT
1011         if (!_windows_vst_plugin_info) {
1012                 windows_vst_refresh ();
1013         }
1014         return *_windows_vst_plugin_info;
1015 #else
1016         return _empty_plugin_info;
1017 #endif
1018 }
1019
1020 ARDOUR::PluginInfoList&
1021 PluginManager::lxvst_plugin_info ()
1022 {
1023 #ifdef LXVST_SUPPORT
1024         assert(_lxvst_plugin_info);
1025         return *_lxvst_plugin_info;
1026 #else
1027         return _empty_plugin_info;
1028 #endif
1029 }
1030
1031 ARDOUR::PluginInfoList&
1032 PluginManager::ladspa_plugin_info ()
1033 {
1034         assert(_ladspa_plugin_info);
1035         return *_ladspa_plugin_info;
1036 }
1037
1038 ARDOUR::PluginInfoList&
1039 PluginManager::lv2_plugin_info ()
1040 {
1041 #ifdef LV2_SUPPORT
1042         assert(_lv2_plugin_info);
1043         return *_lv2_plugin_info;
1044 #else
1045         return _empty_plugin_info;
1046 #endif
1047 }
1048
1049 ARDOUR::PluginInfoList&
1050 PluginManager::au_plugin_info ()
1051 {
1052 #ifdef AUDIOUNIT_SUPPORT
1053         assert(_au_plugin_info);
1054         return *_au_plugin_info;
1055 #else
1056         return _empty_plugin_info;
1057 #endif
1058 }