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