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