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