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