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