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