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