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