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