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