Update classkeys to match new total LuaSignal count (windows only)
[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
30 #include <glib.h>
31 #include "pbd/gstdio_compat.h"
32
33 #ifdef HAVE_LRDF
34 #include <lrdf.h>
35 #endif
36
37 #ifdef WINDOWS_VST_SUPPORT
38 #include "ardour/vst_info_file.h"
39 #include "fst.h"
40 #include "pbd/basename.h"
41 #include <cstring>
42
43 // dll-info
44 #include <sys/stat.h>
45 #include <fcntl.h>
46 #include <unistd.h>
47 #include <stdint.h>
48
49 #endif // WINDOWS_VST_SUPPORT
50
51 #ifdef LXVST_SUPPORT
52 #include "ardour/vst_info_file.h"
53 #include "ardour/linux_vst_support.h"
54 #include "pbd/basename.h"
55 #include <cstring>
56 #endif //LXVST_SUPPORT
57
58 #ifdef MACVST_SUPPORT
59 #include "ardour/vst_info_file.h"
60 #include "ardour/mac_vst_support.h"
61 #include "ardour/mac_vst_plugin.h"
62 #include "pbd/basename.h"
63 #include "pbd/pathexpand.h"
64 #include <cstring>
65 #endif //MACVST_SUPPORT
66
67 #include <glibmm/miscutils.h>
68 #include <glibmm/pattern.h>
69 #include <glibmm/fileutils.h>
70 #include <glibmm/miscutils.h>
71
72 #include "pbd/convert.h"
73 #include "pbd/file_utils.h"
74 #include "pbd/tokenizer.h"
75 #include "pbd/whitespace.h"
76
77 #include "ardour/directory_names.h"
78 #include "ardour/debug.h"
79 #include "ardour/filesystem_paths.h"
80 #include "ardour/ladspa.h"
81 #include "ardour/ladspa_plugin.h"
82 #include "ardour/luascripting.h"
83 #include "ardour/luaproc.h"
84 #include "ardour/plugin.h"
85 #include "ardour/plugin_manager.h"
86 #include "ardour/rc_configuration.h"
87
88 #include "ardour/search_paths.h"
89
90 #ifdef LV2_SUPPORT
91 #include "ardour/lv2_plugin.h"
92 #endif
93
94 #ifdef WINDOWS_VST_SUPPORT
95 #include "ardour/windows_vst_plugin.h"
96 #endif
97
98 #ifdef LXVST_SUPPORT
99 #include "ardour/lxvst_plugin.h"
100 #endif
101
102 #ifdef AUDIOUNIT_SUPPORT
103 #include "ardour/audio_unit.h"
104 #include <Carbon/Carbon.h>
105 #endif
106
107 #include "pbd/error.h"
108 #include "pbd/stl_delete.h"
109
110 #include "pbd/i18n.h"
111
112 #include "ardour/debug.h"
113
114 using namespace ARDOUR;
115 using namespace PBD;
116 using namespace std;
117
118 PluginManager* PluginManager::_instance = 0;
119 std::string PluginManager::scanner_bin_path = "";
120
121 PluginManager&
122 PluginManager::instance()
123 {
124         if (!_instance) {
125                 _instance = new PluginManager;
126         }
127         return *_instance;
128 }
129
130 PluginManager::PluginManager ()
131         : _windows_vst_plugin_info(0)
132         , _lxvst_plugin_info(0)
133         , _mac_vst_plugin_info(0)
134         , _ladspa_plugin_info(0)
135         , _lv2_plugin_info(0)
136         , _au_plugin_info(0)
137         , _lua_plugin_info(0)
138         , _cancel_scan(false)
139         , _cancel_timeout(false)
140 {
141         char* s;
142         string lrdf_path;
143
144 #if defined WINDOWS_VST_SUPPORT || defined LXVST_SUPPORT || defined MACVST_SUPPORT
145         // source-tree (ardev, etc)
146         PBD::Searchpath vstsp(Glib::build_filename(ARDOUR::ardour_dll_directory(), "fst"));
147
148 #ifdef PLATFORM_WINDOWS
149         // on windows the .exe needs to be in the same folder with libardour.dll
150         vstsp += Glib::build_filename(windows_package_directory_path(), "bin");
151 #else
152         // on Unices additional internal-use binaries are deployed to $libdir
153         vstsp += ARDOUR::ardour_dll_directory();
154 #endif
155
156         if (!PBD::find_file (vstsp,
157 #ifdef PLATFORM_WINDOWS
158     #ifdef DEBUGGABLE_SCANNER_APP
159         #if defined(DEBUG) || defined(_DEBUG)
160                                 "ardour-vst-scannerD.exe"
161         #else
162                                 "ardour-vst-scannerRDC.exe"
163         #endif
164     #else
165                                 "ardour-vst-scanner.exe"
166     #endif
167 #else
168                                 "ardour-vst-scanner"
169 #endif
170                                 , scanner_bin_path)) {
171                 PBD::warning << "VST scanner app (ardour-vst-scanner) not found in path " << vstsp.to_string() <<  endmsg;
172         }
173 #endif
174
175         load_statuses ();
176
177         load_tags ();
178
179         if ((s = getenv ("LADSPA_RDF_PATH"))){
180                 lrdf_path = s;
181         }
182
183         if (lrdf_path.length() == 0) {
184                 lrdf_path = "/usr/local/share/ladspa/rdf:/usr/share/ladspa/rdf";
185         }
186
187         add_lrdf_data(lrdf_path);
188         add_ladspa_presets();
189 #ifdef WINDOWS_VST_SUPPORT
190         if (Config->get_use_windows_vst ()) {
191                 add_windows_vst_presets ();
192         }
193 #endif /* WINDOWS_VST_SUPPORT */
194
195 #ifdef LXVST_SUPPORT
196         if (Config->get_use_lxvst()) {
197                 add_lxvst_presets();
198         }
199 #endif /* Native LinuxVST support*/
200
201 #ifdef MACVST_SUPPORT
202         if (Config->get_use_macvst ()) {
203                 add_mac_vst_presets ();
204         }
205 #endif
206
207         if ((s = getenv ("VST_PATH"))) {
208                 windows_vst_path = s;
209         } else if ((s = getenv ("VST_PLUGINS"))) {
210                 windows_vst_path = s;
211         }
212
213         if (windows_vst_path.length() == 0) {
214                 windows_vst_path = vst_search_path ();
215         }
216
217         if ((s = getenv ("LXVST_PATH"))) {
218                 lxvst_path = s;
219         } else if ((s = getenv ("LXVST_PLUGINS"))) {
220                 lxvst_path = s;
221         }
222
223         if (lxvst_path.length() == 0) {
224                 lxvst_path = "/usr/local/lib64/lxvst:/usr/local/lib/lxvst:/usr/lib64/lxvst:/usr/lib/lxvst:"
225                         "/usr/local/lib64/linux_vst:/usr/local/lib/linux_vst:/usr/lib64/linux_vst:/usr/lib/linux_vst:"
226                         "/usr/lib/vst:/usr/local/lib/vst";
227         }
228
229         /* first time setup, use 'default' path */
230         if (Config->get_plugin_path_lxvst() == X_("@default@")) {
231                 Config->set_plugin_path_lxvst(get_default_lxvst_path());
232         }
233         if (Config->get_plugin_path_vst() == X_("@default@")) {
234                 Config->set_plugin_path_vst(get_default_windows_vst_path());
235         }
236
237         if (_instance == 0) {
238                 _instance = this;
239         }
240
241         BootMessage (_("Discovering Plugins"));
242
243         LuaScripting::instance().scripts_changed.connect_same_thread (lua_refresh_connection, boost::bind (&PluginManager::lua_refresh_cb, this));
244 }
245
246
247 PluginManager::~PluginManager()
248 {
249         if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) {
250                 // don't bother, just exit quickly.
251                 delete _windows_vst_plugin_info;
252                 delete _lxvst_plugin_info;
253                 delete _mac_vst_plugin_info;
254                 delete _ladspa_plugin_info;
255                 delete _lv2_plugin_info;
256                 delete _au_plugin_info;
257                 delete _lua_plugin_info;
258         }
259 }
260
261 void
262 PluginManager::refresh (bool cache_only)
263 {
264         Glib::Threads::Mutex::Lock lm (_lock, Glib::Threads::TRY_LOCK);
265
266         if (!lm.locked()) {
267                 return;
268         }
269
270         DEBUG_TRACE (DEBUG::PluginManager, "PluginManager::refresh\n");
271         _cancel_scan = false;
272
273         BootMessage (_("Scanning LADSPA Plugins"));
274         ladspa_refresh ();
275         BootMessage (_("Scanning Lua DSP Processors"));
276         lua_refresh ();
277 #ifdef LV2_SUPPORT
278         BootMessage (_("Scanning LV2 Plugins"));
279         lv2_refresh ();
280 #endif
281 #ifdef WINDOWS_VST_SUPPORT
282         if (Config->get_use_windows_vst()) {
283                 if (cache_only) {
284                         BootMessage (_("Scanning Windows VST Plugins"));
285                 } else {
286                         BootMessage (_("Discovering Windows VST Plugins"));
287                 }
288                 windows_vst_refresh (cache_only);
289         }
290 #endif // WINDOWS_VST_SUPPORT
291
292 #ifdef LXVST_SUPPORT
293         if(Config->get_use_lxvst()) {
294                 if (cache_only) {
295                         BootMessage (_("Scanning Linux VST Plugins"));
296                 } else {
297                         BootMessage (_("Discovering Linux VST Plugins"));
298                 }
299                 lxvst_refresh(cache_only);
300         }
301 #endif //Native linuxVST SUPPORT
302
303 #ifdef MACVST_SUPPORT
304         if(Config->get_use_macvst ()) {
305                 if (cache_only) {
306                         BootMessage (_("Scanning Mac VST Plugins"));
307                 } else {
308                         BootMessage (_("Discovering Mac VST Plugins"));
309                 }
310                 mac_vst_refresh (cache_only);
311         } else if (_mac_vst_plugin_info) {
312                 _mac_vst_plugin_info->clear ();
313         } else {
314                 _mac_vst_plugin_info = new ARDOUR::PluginInfoList();
315         }
316 #endif //Native Mac VST SUPPORT
317
318 #if (defined WINDOWS_VST_SUPPORT || defined LXVST_SUPPORT || defined MACVST_SUPPORT)
319                 if (!cache_only) {
320                         string fn = Glib::build_filename (ARDOUR::user_cache_directory(), VST_BLACKLIST);
321                         if (Glib::file_test (fn, Glib::FILE_TEST_EXISTS)) {
322                                 gchar *bl = NULL;
323                                 if (g_file_get_contents(fn.c_str (), &bl, NULL, NULL)) {
324                                         if (Config->get_verbose_plugin_scan()) {
325                                                 PBD::info << _("VST Blacklist: ") << fn << "\n" << bl << "-----" << endmsg;
326                                         } else {
327                                                 PBD::info << _("VST Blacklist:") << "\n" << bl << "-----" << endmsg;
328                                         }
329                                         g_free (bl);
330                                 }
331                         }
332                 }
333 #endif
334
335 #ifdef AUDIOUNIT_SUPPORT
336         if (cache_only) {
337                 BootMessage (_("Scanning AU Plugins"));
338         } else {
339                 BootMessage (_("Discovering AU Plugins"));
340         }
341         au_refresh (cache_only);
342 #endif
343
344         BootMessage (_("Plugin Scan Complete..."));
345         PluginListChanged (); /* EMIT SIGNAL */
346         PluginScanMessage(X_("closeme"), "", false);
347         _cancel_scan = false;
348 }
349
350 void
351 PluginManager::cancel_plugin_scan ()
352 {
353         _cancel_scan = true;
354 }
355
356 void
357 PluginManager::cancel_plugin_timeout ()
358 {
359         _cancel_timeout = true;
360 }
361
362 void
363 PluginManager::clear_vst_cache ()
364 {
365 #if 1 // clean old cache and error files. (remove this code after 4.3 or 5.0)
366 #ifdef WINDOWS_VST_SUPPORT
367         {
368                 vector<string> fsi_files;
369                 find_files_matching_regex (fsi_files, Config->get_plugin_path_vst(), "\\" VST_EXT_INFOFILE "$", true);
370                 for (vector<string>::iterator i = fsi_files.begin(); i != fsi_files.end (); ++i) {
371                         ::g_unlink(i->c_str());
372                 }
373         }
374         {
375                 vector<string> fsi_files;
376                 find_files_matching_regex (fsi_files, Config->get_plugin_path_vst(), "\\.fsi$", true);
377                 for (vector<string>::iterator i = fsi_files.begin(); i != fsi_files.end (); ++i) {
378                         ::g_unlink(i->c_str());
379                 }
380         }
381         {
382                 vector<string> fsi_files;
383                 find_files_matching_regex (fsi_files, Config->get_plugin_path_vst(), "\\.err$", true);
384                 for (vector<string>::iterator i = fsi_files.begin(); i != fsi_files.end (); ++i) {
385                         ::g_unlink(i->c_str());
386                 }
387         }
388 #endif
389
390 #ifdef LXVST_SUPPORT
391         {
392                 vector<string> fsi_files;
393                 find_files_matching_regex (fsi_files, Config->get_plugin_path_lxvst(), "\\" VST_EXT_INFOFILE "$", true);
394                 for (vector<string>::iterator i = fsi_files.begin(); i != fsi_files.end (); ++i) {
395                         ::g_unlink(i->c_str());
396                 }
397         }
398         {
399                 vector<string> fsi_files;
400                 find_files_matching_regex (fsi_files, Config->get_plugin_path_lxvst(), "\\.fsi$", true);
401                 for (vector<string>::iterator i = fsi_files.begin(); i != fsi_files.end (); ++i) {
402                         ::g_unlink(i->c_str());
403                 }
404         }
405         {
406                 vector<string> fsi_files;
407                 find_files_matching_regex (fsi_files, Config->get_plugin_path_lxvst(), "\\.err$", true);
408                 for (vector<string>::iterator i = fsi_files.begin(); i != fsi_files.end (); ++i) {
409                         ::g_unlink(i->c_str());
410                 }
411         }
412 #endif
413 #if (defined WINDOWS_VST_SUPPORT || defined LXVST_SUPPORT)
414         {
415                 string dir = Glib::build_filename (ARDOUR::user_cache_directory(), "fst_info");
416                 if (Glib::file_test (dir, Glib::FILE_TEST_IS_DIR)) {
417                         PBD::remove_directory (dir);
418                 }
419         }
420 #endif
421 #endif // old cache cleanup
422
423 #if (defined WINDOWS_VST_SUPPORT || defined LXVST_SUPPORT || defined MACVST_SUPPORT)
424         {
425                 string dn = Glib::build_filename (ARDOUR::user_cache_directory(), "vst");
426                 vector<string> fsi_files;
427                 find_files_matching_regex (fsi_files, dn, "\\" VST_EXT_INFOFILE "$", /* user cache is flat, no recursion */ false);
428                 for (vector<string>::iterator i = fsi_files.begin(); i != fsi_files.end (); ++i) {
429                         ::g_unlink(i->c_str());
430                 }
431         }
432 #endif
433 }
434
435 void
436 PluginManager::clear_vst_blacklist ()
437 {
438 #if 1 // remove old blacklist files. (remove this code after 4.3 or 5.0)
439
440 #ifdef WINDOWS_VST_SUPPORT
441         {
442                 vector<string> fsi_files;
443                 find_files_matching_regex (fsi_files, Config->get_plugin_path_vst(), "\\" VST_EXT_BLACKLIST "$", true);
444                 for (vector<string>::iterator i = fsi_files.begin(); i != fsi_files.end (); ++i) {
445                         ::g_unlink(i->c_str());
446                 }
447         }
448 #endif
449
450 #ifdef LXVST_SUPPORT
451         {
452                 vector<string> fsi_files;
453                 find_files_matching_regex (fsi_files, Config->get_plugin_path_lxvst(), "\\" VST_EXT_BLACKLIST "$", true);
454                 for (vector<string>::iterator i = fsi_files.begin(); i != fsi_files.end (); ++i) {
455                         ::g_unlink(i->c_str());
456                 }
457         }
458 #endif
459 #if (defined WINDOWS_VST_SUPPORT || defined LXVST_SUPPORT)
460         {
461                 string dir = Glib::build_filename (ARDOUR::user_cache_directory(), "fst_blacklist");
462                 if (Glib::file_test (dir, Glib::FILE_TEST_IS_DIR)) {
463                         PBD::remove_directory (dir);
464                 }
465         }
466 #endif
467
468 #endif // old blacklist cleanup
469
470 #if (defined WINDOWS_VST_SUPPORT || defined LXVST_SUPPORT || defined MACVST_SUPPORT)
471         {
472                 string fn = Glib::build_filename (ARDOUR::user_cache_directory(), VST_BLACKLIST);
473                 if (Glib::file_test (fn, Glib::FILE_TEST_EXISTS)) {
474                         ::g_unlink (fn.c_str());
475                 }
476         }
477 #endif
478
479 }
480
481 void
482 PluginManager::clear_au_cache ()
483 {
484 #ifdef AUDIOUNIT_SUPPORT
485         AUPluginInfo::clear_cache ();
486 #endif
487 }
488
489 void
490 PluginManager::clear_au_blacklist ()
491 {
492 #ifdef AUDIOUNIT_SUPPORT
493         string fn = Glib::build_filename (ARDOUR::user_cache_directory(), "au_blacklist.txt");
494         if (Glib::file_test (fn, Glib::FILE_TEST_EXISTS)) {
495                 ::g_unlink(fn.c_str());
496         }
497 #endif
498 }
499
500 void
501 PluginManager::lua_refresh ()
502 {
503         if (_lua_plugin_info) {
504                 _lua_plugin_info->clear ();
505         } else {
506                 _lua_plugin_info = new ARDOUR::PluginInfoList ();
507         }
508         ARDOUR::LuaScriptList & _scripts (LuaScripting::instance ().scripts (LuaScriptInfo::DSP));
509         for (LuaScriptList::const_iterator s = _scripts.begin(); s != _scripts.end(); ++s) {
510                 LuaPluginInfoPtr lpi (new LuaPluginInfo(*s));
511                 _lua_plugin_info->push_back (lpi);
512                 set_tags (lpi->type, lpi->unique_id, lpi->category, lpi->name, FromPlug);
513         }
514 }
515
516 void
517 PluginManager::lua_refresh_cb ()
518 {
519         Glib::Threads::Mutex::Lock lm (_lock, Glib::Threads::TRY_LOCK);
520         if (!lm.locked()) {
521                 return;
522         }
523         lua_refresh ();
524         PluginListChanged (); /* EMIT SIGNAL */
525 }
526
527 void
528 PluginManager::ladspa_refresh ()
529 {
530         if (_ladspa_plugin_info) {
531                 _ladspa_plugin_info->clear ();
532         } else {
533                 _ladspa_plugin_info = new ARDOUR::PluginInfoList ();
534         }
535
536         /* allow LADSPA_PATH to augment, not override standard locations */
537
538         /* Only add standard locations to ladspa_path if it doesn't
539          * already contain them. Check for trailing G_DIR_SEPARATOR too.
540          */
541
542         vector<string> ladspa_modules;
543
544         DEBUG_TRACE (DEBUG::PluginManager, string_compose ("LADSPA: search along: [%1]\n", ladspa_search_path().to_string()));
545
546         find_files_matching_pattern (ladspa_modules, ladspa_search_path (), "*.so");
547         find_files_matching_pattern (ladspa_modules, ladspa_search_path (), "*.dylib");
548         find_files_matching_pattern (ladspa_modules, ladspa_search_path (), "*.dll");
549
550         for (vector<std::string>::iterator i = ladspa_modules.begin(); i != ladspa_modules.end(); ++i) {
551                 ARDOUR::PluginScanMessage(_("LADSPA"), *i, false);
552                 ladspa_discover (*i);
553         }
554 }
555
556 #ifdef HAVE_LRDF
557 static bool rdf_filter (const string &str, void* /*arg*/)
558 {
559         return str[0] != '.' &&
560                    ((str.find(".rdf")  == (str.length() - 4)) ||
561             (str.find(".rdfs") == (str.length() - 5)) ||
562                     (str.find(".n3")   == (str.length() - 3)) ||
563                     (str.find(".ttl")  == (str.length() - 4)));
564 }
565 #endif
566
567 void
568 PluginManager::add_ladspa_presets()
569 {
570         add_presets ("ladspa");
571 }
572
573 void
574 PluginManager::add_windows_vst_presets()
575 {
576         add_presets ("windows-vst");
577 }
578
579 void
580 PluginManager::add_mac_vst_presets()
581 {
582         add_presets ("mac-vst");
583 }
584
585 void
586 PluginManager::add_lxvst_presets()
587 {
588         add_presets ("lxvst");
589 }
590
591 void
592 PluginManager::add_presets(string domain)
593 {
594 #ifdef HAVE_LRDF
595         vector<string> presets;
596         vector<string>::iterator x;
597
598         char* envvar;
599         if ((envvar = getenv ("HOME")) == 0) {
600                 return;
601         }
602
603         string path = string_compose("%1/.%2/rdf", envvar, domain);
604         find_files_matching_filter (presets, path, rdf_filter, 0, false, true);
605
606         for (x = presets.begin(); x != presets.end (); ++x) {
607                 string file = "file:" + *x;
608                 if (lrdf_read_file(file.c_str())) {
609                         warning << string_compose(_("Could not parse rdf file: %1"), *x) << endmsg;
610                 }
611         }
612
613 #endif
614 }
615
616 void
617 PluginManager::add_lrdf_data (const string &path)
618 {
619 #ifdef HAVE_LRDF
620         vector<string> rdf_files;
621         vector<string>::iterator x;
622
623         find_files_matching_filter (rdf_files, path, rdf_filter, 0, false, true);
624
625         for (x = rdf_files.begin(); x != rdf_files.end (); ++x) {
626                 const string uri(string("file://") + *x);
627
628                 if (lrdf_read_file(uri.c_str())) {
629                         warning << "Could not parse rdf file: " << uri << endmsg;
630                 }
631         }
632 #endif
633 }
634
635 int
636 PluginManager::ladspa_discover (string path)
637 {
638         DEBUG_TRACE (DEBUG::PluginManager, string_compose ("Checking for LADSPA plugin at %1\n", path));
639
640         Glib::Module module(path);
641         const LADSPA_Descriptor *descriptor;
642         LADSPA_Descriptor_Function dfunc;
643         void* func = 0;
644
645         if (!module) {
646                 error << string_compose(_("LADSPA: cannot load module \"%1\" (%2)"),
647                         path, Glib::Module::get_last_error()) << endmsg;
648                 return -1;
649         }
650
651
652         if (!module.get_symbol("ladspa_descriptor", func)) {
653                 error << string_compose(_("LADSPA: module \"%1\" has no descriptor function."), path) << endmsg;
654                 error << Glib::Module::get_last_error() << endmsg;
655                 return -1;
656         }
657
658         dfunc = (LADSPA_Descriptor_Function)func;
659
660         DEBUG_TRACE (DEBUG::PluginManager, string_compose ("LADSPA plugin found at %1\n", path));
661
662         for (uint32_t i = 0; ; ++i) {
663                 /* if a ladspa plugin allocates memory here
664                  * it is never free()ed (or plugin-dependent only when unloading).
665                  * For some plugins memory allocated is incremental, we should
666                  * avoid re-scanning plugins and file bug reports.
667                  */
668                 if ((descriptor = dfunc (i)) == 0) {
669                         break;
670                 }
671
672                 if (!ladspa_plugin_whitelist.empty()) {
673                         if (find (ladspa_plugin_whitelist.begin(), ladspa_plugin_whitelist.end(), descriptor->UniqueID) == ladspa_plugin_whitelist.end()) {
674                                 continue;
675                         }
676                 }
677
678                 PluginInfoPtr info(new LadspaPluginInfo);
679                 info->name = descriptor->Name;
680                 info->category = get_ladspa_category(descriptor->UniqueID);
681                 info->path = path;
682                 info->index = i;
683                 info->n_inputs = ChanCount();
684                 info->n_outputs = ChanCount();
685                 info->type = ARDOUR::LADSPA;
686
687                 string::size_type pos = 0;
688                 string creator = descriptor->Maker;
689                 /* stupid LADSPA creator strings */
690 #ifdef PLATFORM_WINDOWS
691                 while (pos < creator.length() && creator[pos] > -2 && creator[pos] < 256 && (isalnum (creator[pos]) || isspace (creator[pos]) || creator[pos] == '.')) ++pos;
692 #else
693                 while (pos < creator.length() && (isalnum (creator[pos]) || isspace (creator[pos]) || creator[pos] == '.')) ++pos;
694 #endif
695
696                 /* If there were too few characters to create a
697                  * meaningful name, mark this creator as 'Unknown'
698                  */
699                 if (creator.length() < 2 || pos < 3) {
700                         info->creator = "Unknown";
701                 } else{
702                         info->creator = creator.substr (0, pos);
703                 }
704
705                 char buf[32];
706                 snprintf (buf, sizeof (buf), "%lu", descriptor->UniqueID);
707                 info->unique_id = buf;
708
709                 for (uint32_t n=0; n < descriptor->PortCount; ++n) {
710                         if (LADSPA_IS_PORT_AUDIO (descriptor->PortDescriptors[n])) {
711                                 if (LADSPA_IS_PORT_INPUT (descriptor->PortDescriptors[n])) {
712                                         info->n_inputs.set_audio(info->n_inputs.n_audio() + 1);
713                                 }
714                                 else if (LADSPA_IS_PORT_OUTPUT (descriptor->PortDescriptors[n])) {
715                                         info->n_outputs.set_audio(info->n_outputs.n_audio() + 1);
716                                 }
717                         }
718                 }
719
720                 if(_ladspa_plugin_info->empty()){
721                         _ladspa_plugin_info->push_back (info);
722                 }
723
724                 //Ensure that the plugin is not already in the plugin list.
725
726                 bool found = false;
727
728                 for (PluginInfoList::const_iterator i = _ladspa_plugin_info->begin(); i != _ladspa_plugin_info->end(); ++i) {
729                         if(0 == info->unique_id.compare((*i)->unique_id)){
730                               found = true;
731                         }
732                 }
733
734                 if(!found){
735                     _ladspa_plugin_info->push_back (info);
736                         set_tags (info->type, info->unique_id, info->category, info->name, FromPlug);
737                 }
738
739                 DEBUG_TRACE (DEBUG::PluginManager, string_compose ("Found LADSPA plugin, name: %1, Inputs: %2, Outputs: %3\n", info->name, info->n_inputs, info->n_outputs));
740         }
741
742 // GDB WILL NOT LIKE YOU IF YOU DO THIS
743 //      dlclose (module);
744
745         return 0;
746 }
747
748 string
749 PluginManager::get_ladspa_category (uint32_t plugin_id)
750 {
751 #ifdef HAVE_LRDF
752         char buf[256];
753         lrdf_statement pattern;
754
755         snprintf(buf, sizeof(buf), "%s%" PRIu32, LADSPA_BASE, plugin_id);
756         pattern.subject = buf;
757         pattern.predicate = const_cast<char*>(RDF_TYPE);
758         pattern.object = 0;
759         pattern.object_type = lrdf_uri;
760
761         lrdf_statement* matches1 = lrdf_matches (&pattern);
762
763         if (!matches1) {
764                 return "Unknown";
765         }
766
767         pattern.subject = matches1->object;
768         pattern.predicate = const_cast<char*>(LADSPA_BASE "hasLabel");
769         pattern.object = 0;
770         pattern.object_type = lrdf_literal;
771
772         lrdf_statement* matches2 = lrdf_matches (&pattern);
773         lrdf_free_statements(matches1);
774
775         if (!matches2) {
776                 return ("Unknown");
777         }
778
779         string label = matches2->object;
780         lrdf_free_statements(matches2);
781
782         /* Kludge LADSPA class names to be singular and match LV2 class names.
783            This avoids duplicate plugin menus for every class, which is necessary
784            to make the plugin category menu at all usable, but is obviously a
785            filthy kludge.
786
787            In the short term, lrdf could be updated so the labels match and a new
788            release made. To support both specs, we should probably be mapping the
789            URIs to the same category in code and perhaps tweaking that hierarchy
790            dynamically to suit the user. Personally, I (drobilla) think that time
791            is better spent replacing the little-used LRDF.
792
793            In the longer term, we will abandon LRDF entirely in favour of LV2 and
794            use that class hierarchy. Aside from fixing this problem properly, that
795            will also allow for translated labels. SWH plugins have been LV2 for
796            ages; TAP needs porting. I don't know of anything else with LRDF data.
797         */
798         if (label == "Utilities") {
799                 return "Utility";
800         } else if (label == "Pitch shifters") {
801                 return "Pitch Shifter";
802         } else if (label != "Dynamics" && label != "Chorus"
803                    &&label[label.length() - 1] == 's'
804                    && label[label.length() - 2] != 's') {
805                 return label.substr(0, label.length() - 1);
806         } else {
807                 return label;
808         }
809 #else
810                 return ("Unknown");
811 #endif
812 }
813
814 #ifdef LV2_SUPPORT
815 void
816 PluginManager::lv2_refresh ()
817 {
818         DEBUG_TRACE (DEBUG::PluginManager, "LV2: refresh\n");
819         delete _lv2_plugin_info;
820         _lv2_plugin_info = LV2PluginInfo::discover();
821
822         for (PluginInfoList::iterator i = _lv2_plugin_info->begin(); i != _lv2_plugin_info->end(); ++i) {
823                 set_tags ((*i)->type, (*i)->unique_id, (*i)->category, (*i)->name, FromPlug);
824         }
825 }
826 #endif
827
828 #ifdef AUDIOUNIT_SUPPORT
829 void
830 PluginManager::au_refresh (bool cache_only)
831 {
832         DEBUG_TRACE (DEBUG::PluginManager, "AU: refresh\n");
833
834         // disable automatic discovery in case we crash
835         bool discover_at_start = Config->get_discover_audio_units ();
836         Config->set_discover_audio_units (false);
837         Config->save_state();
838
839         delete _au_plugin_info;
840         _au_plugin_info = AUPluginInfo::discover(cache_only && !discover_at_start);
841
842         // successful scan re-enabled automatic discovery if it was set
843         Config->set_discover_audio_units (discover_at_start);
844         Config->save_state();
845
846         for (PluginInfoList::iterator i = _au_plugin_info->begin(); i != _au_plugin_info->end(); ++i) {
847                 set_tags ((*i)->type, (*i)->unique_id, (*i)->category, (*i)->name, FromPlug);
848         }
849 }
850
851 #endif
852
853 #ifdef WINDOWS_VST_SUPPORT
854
855 void
856 PluginManager::windows_vst_refresh (bool cache_only)
857 {
858         if (_windows_vst_plugin_info) {
859                 _windows_vst_plugin_info->clear ();
860         } else {
861                 _windows_vst_plugin_info = new ARDOUR::PluginInfoList();
862         }
863
864         windows_vst_discover_from_path (Config->get_plugin_path_vst(), cache_only);
865 }
866
867 static bool windows_vst_filter (const string& str, void * /*arg*/)
868 {
869         /* Not a dotfile, has a prefix before a period, suffix is "dll" */
870         return str[0] != '.' && str.length() > 4 && strings_equal_ignore_case (".dll", str.substr(str.length() - 4));
871 }
872
873 int
874 PluginManager::windows_vst_discover_from_path (string path, bool cache_only)
875 {
876         vector<string> plugin_objects;
877         vector<string>::iterator x;
878         int ret = 0;
879
880         DEBUG_TRACE (DEBUG::PluginManager, string_compose ("Discovering Windows VST plugins along %1\n", path));
881
882         if (Session::get_disable_all_loaded_plugins ()) {
883                 info << _("Disabled WindowsVST scan (safe mode)") << endmsg;
884                 return -1;
885         }
886
887         if (Config->get_verbose_plugin_scan()) {
888                 info << string_compose (_("--- Windows VST plugins Scan: %1"), path) << endmsg;
889         }
890
891         find_files_matching_filter (plugin_objects, path, windows_vst_filter, 0, false, true, true);
892
893         for (x = plugin_objects.begin(); x != plugin_objects.end (); ++x) {
894                 ARDOUR::PluginScanMessage(_("VST"), *x, !cache_only && !cancelled());
895                 windows_vst_discover (*x, cache_only || cancelled());
896         }
897
898         if (Config->get_verbose_plugin_scan()) {
899                 info << _("--- Windows VST plugins Scan Done") << endmsg;
900         }
901
902         return ret;
903 }
904
905 static std::string dll_info (std::string path) {
906         std::string rv;
907         uint8_t buf[68];
908         uint16_t type = 0;
909         off_t pe_hdr_off = 0;
910
911         int fd = g_open(path.c_str(), O_RDONLY, 0444);
912
913         if (fd < 0) {
914                 return _("cannot open dll"); // TODO strerror()
915         }
916
917         if (68 != read (fd, buf, 68)) {
918                 rv = _("invalid dll, file too small");
919                 goto errorout;
920         }
921         if (buf[0] != 'M' && buf[1] != 'Z') {
922                 rv = _("not a dll");
923                 goto errorout;
924         }
925
926         pe_hdr_off = *((int32_t*) &buf[60]);
927         if (pe_hdr_off !=lseek (fd, pe_hdr_off, SEEK_SET)) {
928                 rv = _("cannot determine dll type");
929                 goto errorout;
930         }
931         if (6 != read (fd, buf, 6)) {
932                 rv = _("cannot read dll PE header");
933                 goto errorout;
934         }
935
936         if (buf[0] != 'P' && buf[1] != 'E') {
937                 rv = _("invalid dll PE header");
938                 goto errorout;
939         }
940
941         type = *((uint16_t*) &buf[4]);
942         switch (type) {
943                 case 0x014c:
944                         rv = _("i386 (32-bit)");
945                         break;
946                 case  0x0200:
947                         rv = _("Itanium");
948                         break;
949                 case 0x8664:
950                         rv = _("x64 (64-bit)");
951                         break;
952                 case 0:
953                         rv = _("Native Architecture");
954                         break;
955                 default:
956                         rv = _("Unknown Architecture");
957                         break;
958         }
959 errorout:
960         assert (rv.length() > 0);
961         close (fd);
962         return rv;
963 }
964
965 int
966 PluginManager::windows_vst_discover (string path, bool cache_only)
967 {
968         DEBUG_TRACE (DEBUG::PluginManager, string_compose ("windows_vst_discover '%1'\n", path));
969
970         if (Config->get_verbose_plugin_scan()) {
971                 if (cache_only) {
972                         info << string_compose (_(" *  %1 (cache only)"), path) << endmsg;
973                 } else {
974                         info << string_compose (_(" *  %1 - %2"), path, dll_info (path)) << endmsg;
975                 }
976         }
977
978         _cancel_timeout = false;
979         vector<VSTInfo*> * finfos = vstfx_get_info_fst (const_cast<char *> (path.c_str()),
980                         cache_only ? VST_SCAN_CACHE_ONLY : VST_SCAN_USE_APP);
981
982         // TODO  get extended error messae from vstfx_get_info_fst() e.g  blacklisted, 32/64bit compat,
983         // .err file scanner output etc.
984
985         if (finfos->empty()) {
986                 DEBUG_TRACE (DEBUG::PluginManager, string_compose ("Cannot get Windows VST information from '%1'\n", path));
987                 if (Config->get_verbose_plugin_scan()) {
988                         info << _(" -> Cannot get Windows VST information, plugin ignored.") << endmsg;
989                 }
990                 return -1;
991         }
992
993         uint32_t discovered = 0;
994         for (vector<VSTInfo *>::iterator x = finfos->begin(); x != finfos->end(); ++x) {
995                 VSTInfo* finfo = *x;
996
997                 if (!finfo->canProcessReplacing) {
998                         warning << string_compose (_("VST plugin %1 does not support processReplacing, and cannot be used in %2 at this time"),
999                                                          finfo->name, PROGRAM_NAME)
1000                                 << endl;
1001                         continue;
1002                 }
1003
1004                 PluginInfoPtr info (new WindowsVSTPluginInfo (finfo));
1005                 info->path = path;
1006
1007                 /* what a joke freeware VST is */
1008                 if (!strcasecmp ("The Unnamed plugin", finfo->name)) {
1009                         info->name = PBD::basename_nosuffix (path);
1010                 }
1011
1012                 /* if we don't have any tags for this plugin, make some up. */
1013                 set_tags (info->type, info->unique_id, info->category, info->name, FromPlug);
1014
1015                 // TODO: check dup-IDs (lxvst AND windows vst)
1016                 bool duplicate = false;
1017
1018                 if (!_windows_vst_plugin_info->empty()) {
1019                         for (PluginInfoList::iterator i =_windows_vst_plugin_info->begin(); i != _windows_vst_plugin_info->end(); ++i) {
1020                                 if ((info->type == (*i)->type) && (info->unique_id == (*i)->unique_id)) {
1021                                         warning << string_compose (_("Ignoring duplicate Windows VST plugin \"%1\""), info->name) << endmsg;
1022                                         duplicate = true;
1023                                         break;
1024                                 }
1025                         }
1026                 }
1027
1028                 if (!duplicate) {
1029                         DEBUG_TRACE (DEBUG::PluginManager, string_compose ("Windows VST plugin ID '%1'\n", info->unique_id));
1030                         _windows_vst_plugin_info->push_back (info);
1031                         discovered++;
1032                         if (Config->get_verbose_plugin_scan()) {
1033                                 PBD::info << string_compose (_(" -> OK (VST Plugin \"%1\" was added)."), info->name) << endmsg;
1034                         }
1035                 }
1036         }
1037
1038         vstfx_free_info_list (finfos);
1039         return discovered > 0 ? 0 : -1;
1040 }
1041
1042 #endif // WINDOWS_VST_SUPPORT
1043
1044 #ifdef MACVST_SUPPORT
1045 void
1046 PluginManager::mac_vst_refresh (bool cache_only)
1047 {
1048         if (_mac_vst_plugin_info) {
1049                 _mac_vst_plugin_info->clear ();
1050         } else {
1051                 _mac_vst_plugin_info = new ARDOUR::PluginInfoList();
1052         }
1053
1054         mac_vst_discover_from_path ("~/Library/Audio/Plug-Ins/VST:/Library/Audio/Plug-Ins/VST", cache_only);
1055 }
1056
1057 static bool mac_vst_filter (const string& str)
1058 {
1059         string plist = Glib::build_filename (str, "Contents", "Info.plist");
1060         if (!Glib::file_test (plist, Glib::FILE_TEST_IS_REGULAR)) {
1061                 return false;
1062         }
1063         return str[0] != '.' && str.length() > 4 && strings_equal_ignore_case (".vst", str.substr(str.length() - 4));
1064 }
1065
1066 int
1067 PluginManager::mac_vst_discover_from_path (string path, bool cache_only)
1068 {
1069         if (Session::get_disable_all_loaded_plugins ()) {
1070                 info << _("Disabled MacVST scan (safe mode)") << endmsg;
1071                 return -1;
1072         }
1073
1074         Searchpath paths (path);
1075         /* customized version of run_functor_for_paths() */
1076         for (vector<string>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
1077                 string expanded_path = path_expand (*i);
1078                 if (!Glib::file_test (expanded_path, Glib::FILE_TEST_IS_DIR)) continue;
1079                 try {
1080                         Glib::Dir dir(expanded_path);
1081                         for (Glib::DirIterator di = dir.begin(); di != dir.end(); di++) {
1082                                 string fullpath = Glib::build_filename (expanded_path, *di);
1083
1084                                 /* we're only interested in bundles */
1085                                 if (!Glib::file_test (fullpath, Glib::FILE_TEST_IS_DIR)) {
1086                                         continue;
1087                                 }
1088
1089                                 if (mac_vst_filter (fullpath)) {
1090                                         ARDOUR::PluginScanMessage(_("MacVST"), fullpath, !cache_only && !cancelled());
1091                                         mac_vst_discover (fullpath, cache_only || cancelled());
1092                                         continue;
1093                                 }
1094
1095                                 /* don't descend into AU bundles in the VST dir */
1096                                 if (fullpath[0] == '.' || (fullpath.length() > 10 && strings_equal_ignore_case (".component", fullpath.substr(fullpath.length() - 10)))) {
1097                                         continue;
1098                                 }
1099
1100                                 /* recurse */
1101                                 mac_vst_discover_from_path (fullpath, cache_only);
1102                         }
1103                 } catch (Glib::FileError& err) { }
1104         }
1105
1106         return 0;
1107 }
1108
1109 int
1110 PluginManager::mac_vst_discover (string path, bool cache_only)
1111 {
1112         DEBUG_TRACE (DEBUG::PluginManager, string_compose ("checking apparent MacVST plugin at %1\n", path));
1113
1114         _cancel_timeout = false;
1115
1116         vector<VSTInfo*>* finfos = vstfx_get_info_mac (const_cast<char *> (path.c_str()),
1117                         cache_only ? VST_SCAN_CACHE_ONLY : VST_SCAN_USE_APP);
1118
1119         if (finfos->empty()) {
1120                 DEBUG_TRACE (DEBUG::PluginManager, string_compose ("Cannot get Mac VST information from '%1'\n", path));
1121                 return -1;
1122         }
1123
1124         uint32_t discovered = 0;
1125         for (vector<VSTInfo *>::iterator x = finfos->begin(); x != finfos->end(); ++x) {
1126                 VSTInfo* finfo = *x;
1127
1128                 if (!finfo->canProcessReplacing) {
1129                         warning << string_compose (_("Mac VST plugin %1 does not support processReplacing, and so cannot be used in %2 at this time"),
1130                                                          finfo->name, PROGRAM_NAME)
1131                                 << endl;
1132                         continue;
1133                 }
1134
1135                 PluginInfoPtr info (new MacVSTPluginInfo (finfo));
1136                 info->path = path;
1137
1138                 /* if we don't have any tags for this plugin, make some up. */
1139                 set_tags (info->type, info->unique_id, info->category, info->name, FromPlug);
1140
1141                 bool duplicate = false;
1142                 if (!_mac_vst_plugin_info->empty()) {
1143                         for (PluginInfoList::iterator i =_mac_vst_plugin_info->begin(); i != _mac_vst_plugin_info->end(); ++i) {
1144                                 if ((info->type == (*i)->type)&&(info->unique_id == (*i)->unique_id)) {
1145                                         warning << "Ignoring duplicate Mac VST plugin " << info->name << "\n";
1146                                         duplicate = true;
1147                                         break;
1148                                 }
1149                         }
1150                 }
1151
1152                 if (!duplicate) {
1153                         _mac_vst_plugin_info->push_back (info);
1154                         discovered++;
1155                 }
1156         }
1157
1158         vstfx_free_info_list (finfos);
1159         return discovered > 0 ? 0 : -1;
1160 }
1161
1162 #endif // MAC_VST_SUPPORT
1163
1164 #ifdef LXVST_SUPPORT
1165
1166 void
1167 PluginManager::lxvst_refresh (bool cache_only)
1168 {
1169         if (_lxvst_plugin_info) {
1170                 _lxvst_plugin_info->clear ();
1171         } else {
1172                 _lxvst_plugin_info = new ARDOUR::PluginInfoList();
1173         }
1174
1175         lxvst_discover_from_path (Config->get_plugin_path_lxvst(), cache_only);
1176 }
1177
1178 static bool lxvst_filter (const string& str, void *)
1179 {
1180         /* Not a dotfile, has a prefix before a period, suffix is "so" */
1181
1182         return str[0] != '.' && (str.length() > 3 && str.find (".so") == (str.length() - 3));
1183 }
1184
1185 int
1186 PluginManager::lxvst_discover_from_path (string path, bool cache_only)
1187 {
1188         vector<string> plugin_objects;
1189         vector<string>::iterator x;
1190         int ret = 0;
1191
1192         if (Session::get_disable_all_loaded_plugins ()) {
1193                 info << _("Disabled LinuxVST scan (safe mode)") << endmsg;
1194                 return -1;
1195         }
1196
1197 #ifndef NDEBUG
1198         (void) path;
1199 #endif
1200
1201         DEBUG_TRACE (DEBUG::PluginManager, string_compose ("Discovering linuxVST plugins along %1\n", path));
1202
1203         find_files_matching_filter (plugin_objects, Config->get_plugin_path_lxvst(), lxvst_filter, 0, false, true, true);
1204
1205         for (x = plugin_objects.begin(); x != plugin_objects.end (); ++x) {
1206                 ARDOUR::PluginScanMessage(_("LXVST"), *x, !cache_only && !cancelled());
1207                 lxvst_discover (*x, cache_only || cancelled());
1208         }
1209
1210         return ret;
1211 }
1212
1213 int
1214 PluginManager::lxvst_discover (string path, bool cache_only)
1215 {
1216         DEBUG_TRACE (DEBUG::PluginManager, string_compose ("checking apparent LXVST plugin at %1\n", path));
1217
1218         _cancel_timeout = false;
1219         vector<VSTInfo*> * finfos = vstfx_get_info_lx (const_cast<char *> (path.c_str()),
1220                         cache_only ? VST_SCAN_CACHE_ONLY : VST_SCAN_USE_APP);
1221
1222         if (finfos->empty()) {
1223                 DEBUG_TRACE (DEBUG::PluginManager, string_compose ("Cannot get Linux VST information from '%1'\n", path));
1224                 return -1;
1225         }
1226
1227         uint32_t discovered = 0;
1228         for (vector<VSTInfo *>::iterator x = finfos->begin(); x != finfos->end(); ++x) {
1229                 VSTInfo* finfo = *x;
1230
1231                 if (!finfo->canProcessReplacing) {
1232                         warning << string_compose (_("linuxVST plugin %1 does not support processReplacing, and so cannot be used in %2 at this time"),
1233                                                          finfo->name, PROGRAM_NAME)
1234                                 << endl;
1235                         continue;
1236                 }
1237
1238                 PluginInfoPtr info(new LXVSTPluginInfo (finfo));
1239                 info->path = path;
1240
1241                 if (!strcasecmp ("The Unnamed plugin", finfo->name)) {
1242                         info->name = PBD::basename_nosuffix (path);
1243                 }
1244
1245                 set_tags (info->type, info->unique_id, info->category, info->name, FromPlug);
1246
1247                 /* Make sure we don't find the same plugin in more than one place along
1248                  * the LXVST_PATH We can't use a simple 'find' because the path is included
1249                  * in the PluginInfo, and that is the one thing we can be sure MUST be
1250                  * different if a duplicate instance is found.  So we just compare the type
1251                  * and unique ID (which for some VSTs isn't actually unique...)
1252                  */
1253
1254                 // TODO: check dup-IDs with windowsVST, too
1255                 bool duplicate = false;
1256                 if (!_lxvst_plugin_info->empty()) {
1257                         for (PluginInfoList::iterator i =_lxvst_plugin_info->begin(); i != _lxvst_plugin_info->end(); ++i) {
1258                                 if ((info->type == (*i)->type)&&(info->unique_id == (*i)->unique_id)) {
1259                                         warning << "Ignoring duplicate Linux VST plugin " << info->name << "\n";
1260                                         duplicate = true;
1261                                         break;
1262                                 }
1263                         }
1264                 }
1265
1266                 if (!duplicate) {
1267                         _lxvst_plugin_info->push_back (info);
1268                         discovered++;
1269                 }
1270         }
1271
1272         vstfx_free_info_list (finfos);
1273         return discovered > 0 ? 0 : -1;
1274 }
1275
1276 #endif // LXVST_SUPPORT
1277
1278
1279 PluginManager::PluginStatusType
1280 PluginManager::get_status (const PluginInfoPtr& pi) const
1281 {
1282         PluginStatus ps (pi->type, pi->unique_id);
1283         PluginStatusList::const_iterator i =  find (statuses.begin(), statuses.end(), ps);
1284         if (i ==  statuses.end()) {
1285                 return Normal;
1286         } else {
1287                 return i->status;
1288         }
1289 }
1290
1291 void
1292 PluginManager::save_statuses ()
1293 {
1294         std::string path = Glib::build_filename (user_plugin_metadata_dir(), "plugin_statuses");
1295         stringstream ofs;
1296
1297         for (PluginStatusList::iterator i = statuses.begin(); i != statuses.end(); ++i) {
1298                 switch ((*i).type) {
1299                 case LADSPA:
1300                         ofs << "LADSPA";
1301                         break;
1302                 case AudioUnit:
1303                         ofs << "AudioUnit";
1304                         break;
1305                 case LV2:
1306                         ofs << "LV2";
1307                         break;
1308                 case Windows_VST:
1309                         ofs << "Windows-VST";
1310                         break;
1311                 case LXVST:
1312                         ofs << "LXVST";
1313                         break;
1314                 case MacVST:
1315                         ofs << "MacVST";
1316                         break;
1317                 case Lua:
1318                         ofs << "Lua";
1319                         break;
1320                 }
1321
1322                 ofs << ' ';
1323
1324                 switch ((*i).status) {
1325                 case Normal:
1326                         ofs << "Normal";
1327                         break;
1328                 case Favorite:
1329                         ofs << "Favorite";
1330                         break;
1331                 case Hidden:
1332                         ofs << "Hidden";
1333                         break;
1334                 }
1335
1336                 ofs << ' ';
1337
1338                 ofs << (*i).unique_id;;
1339                 ofs << endl;
1340         }
1341         g_file_set_contents (path.c_str(), ofs.str().c_str(), -1, NULL);
1342 }
1343
1344 void
1345 PluginManager::load_statuses ()
1346 {
1347         std::string path;
1348         find_file (plugin_metadata_search_path(), "plugin_statuses", path);  //note: if no user folder is found, this will find the resources path
1349         gchar *fbuf = NULL;
1350         if (!g_file_get_contents (path.c_str(), &fbuf, NULL, NULL))  {
1351                 return;
1352         }
1353         stringstream ifs (fbuf);
1354         g_free (fbuf);
1355
1356         std::string stype;
1357         std::string sstatus;
1358         std::string id;
1359         PluginType type;
1360         PluginStatusType status;
1361         char buf[1024];
1362
1363         while (ifs) {
1364
1365                 ifs >> stype;
1366                 if (!ifs) {
1367                         break;
1368
1369                 }
1370
1371                 ifs >> sstatus;
1372                 if (!ifs) {
1373                         break;
1374
1375                 }
1376
1377                 /* rest of the line is the plugin ID */
1378
1379                 ifs.getline (buf, sizeof (buf), '\n');
1380                 if (!ifs) {
1381                         break;
1382                 }
1383
1384                 if (sstatus == "Normal") {
1385                         status = Normal;
1386                 } else if (sstatus == "Favorite") {
1387                         status = Favorite;
1388                 } else if (sstatus == "Hidden") {
1389                         status = Hidden;
1390                 } else {
1391                         error << string_compose (_("unknown plugin status type \"%1\" - all entries ignored"), sstatus)
1392                                   << endmsg;
1393                         statuses.clear ();
1394                         break;
1395                 }
1396
1397                 if (stype == "LADSPA") {
1398                         type = LADSPA;
1399                 } else if (stype == "AudioUnit") {
1400                         type = AudioUnit;
1401                 } else if (stype == "LV2") {
1402                         type = LV2;
1403                 } else if (stype == "Windows-VST") {
1404                         type = Windows_VST;
1405                 } else if (stype == "LXVST") {
1406                         type = LXVST;
1407                 } else if (stype == "MacVST") {
1408                         type = MacVST;
1409                 } else if (stype == "Lua") {
1410                         type = Lua;
1411                 } else {
1412                         error << string_compose (_("unknown plugin type \"%1\" - ignored"), stype)
1413                               << endmsg;
1414                         continue;
1415                 }
1416
1417                 id = buf;
1418                 strip_whitespace_edges (id);
1419                 set_status (type, id, status);
1420         }
1421 }
1422
1423 void
1424 PluginManager::set_status (PluginType t, string id, PluginStatusType status)
1425 {
1426         PluginStatus ps (t, id, status);
1427         statuses.erase (ps);
1428
1429         if (status != Normal) {
1430                 statuses.insert (ps);
1431         }
1432
1433         PluginStatusChanged (t, id, status); /* EMIT SIGNAL */
1434 }
1435
1436 PluginType
1437 PluginManager::to_generic_vst (const PluginType t)
1438 {
1439         switch (t) {
1440                 case Windows_VST:
1441                 case LXVST:
1442                 case MacVST:
1443                         return LXVST;
1444                 default:
1445                         break;
1446         }
1447         return t;
1448 }
1449
1450 struct SortByTag {
1451         bool operator() (std::string a, std::string b) {
1452                 return a.compare (b) < 0;
1453         }
1454 };
1455
1456 vector<std::string>
1457 PluginManager::get_tags (const PluginInfoPtr& pi) const
1458 {
1459         vector<std::string> tags;
1460
1461         PluginTag ps (to_generic_vst(pi->type), pi->unique_id, "", "", FromPlug);
1462         PluginTagList::const_iterator i = find (ptags.begin(), ptags.end(), ps);
1463         if (i != ptags.end ()) {
1464                 PBD::tokenize (i->tags, string(" "), std::back_inserter (tags), true);
1465                 SortByTag sorter;
1466                 sort (tags.begin(), tags.end(), sorter);
1467         }
1468         return tags;
1469 }
1470
1471 std::string
1472 PluginManager::get_tags_as_string (PluginInfoPtr const& pi) const
1473 {
1474         std::string ret;
1475
1476         vector<std::string> tags = get_tags(pi);
1477         for (vector<string>::iterator t = tags.begin(); t != tags.end(); ++t) {
1478                 if (t != tags.begin ()) {
1479                         ret.append(" ");
1480                 }
1481                 ret.append(*t);
1482         }
1483
1484         return ret;
1485 }
1486
1487 std::string
1488 PluginManager::user_plugin_metadata_dir () const
1489 {
1490         std::string dir = Glib::build_filename (user_config_directory(), plugin_metadata_dir_name);
1491         g_mkdir_with_parents (dir.c_str(), 0744);
1492         return dir;
1493 }
1494
1495 bool
1496 PluginManager::load_plugin_order_file (XMLNode &n) const
1497 {
1498         std::string path = Glib::build_filename (user_plugin_metadata_dir(), "plugin_order");
1499
1500         info << string_compose (_("Loading plugin order file %1"), path) << endmsg;
1501         if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
1502                 return false;
1503         }
1504
1505         XMLTree tree;
1506         if (tree.read (path)) {
1507                 n = *(tree.root());
1508                 return true;
1509         } else {
1510                 error << string_compose (_("Cannot parse Plugin Order info from %1"), path) << endmsg;
1511                 return false;
1512         }
1513 }
1514
1515
1516 void
1517 PluginManager::save_plugin_order_file (XMLNode &elem) const
1518 {
1519         std::string path = Glib::build_filename (user_plugin_metadata_dir(), "plugin_order");
1520
1521         info << string_compose (_("Saving plugin order file %1"), path) << endmsg;
1522
1523         XMLTree tree;
1524         tree.set_root (&elem);
1525         if (!tree.write (path)) {
1526                 error << string_compose (_("Could not save Plugin Order info to %1"), path) << endmsg;
1527         }
1528         tree.set_root (0);  //note: must disconnect the elem from XMLTree, or it will try to delete memory it didn't allocate
1529 }
1530
1531
1532 void
1533 PluginManager::save_tags ()
1534 {
1535         std::string path = Glib::build_filename (user_plugin_metadata_dir(), "plugin_tags");
1536         XMLNode* root = new XMLNode (X_("PluginTags"));
1537
1538         for (PluginTagList::iterator i = ptags.begin(); i != ptags.end(); ++i) {
1539                 if ( (*i).tagtype == FromFactoryFile || (*i).tagtype == FromUserFile ) {
1540                         /* user file should contain only plugins that are (a) newly user-tagged or (b) previously unknown */
1541                         continue;
1542                 }
1543                 XMLNode* node = new XMLNode (X_("Plugin"));
1544                 node->set_property (X_("type"), to_generic_vst ((*i).type));
1545                 node->set_property (X_("id"), (*i).unique_id);
1546                 node->set_property (X_("tags"), (*i).tags);
1547                 node->set_property (X_("name"), (*i).name);
1548                 if ( (*i).tagtype >= FromUserFile ) {
1549                         node->set_property (X_("user-set"), "1");
1550                 }
1551                 root->add_child_nocopy (*node);
1552         }
1553
1554         XMLTree tree;
1555         tree.set_root (root);
1556         if (!tree.write (path)) {
1557                 error << string_compose (_("Could not save Plugin Tags info to %1"), path) << endmsg;
1558         }
1559 }
1560
1561 void
1562 PluginManager::load_tags ()
1563 {
1564         vector<std::string> tmp;
1565         find_files_matching_pattern (tmp, plugin_metadata_search_path (), "plugin_tags");
1566
1567         for (vector<std::string>::const_reverse_iterator p = tmp.rbegin ();
1568                         p != (vector<std::string>::const_reverse_iterator)tmp.rend(); ++p) {
1569                 std::string path = *p;
1570                 info << string_compose (_("Loading plugin meta data file %1"), path) << endmsg;
1571                 if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
1572                         return;
1573                 }
1574
1575                 XMLTree tree;
1576                 if (!tree.read (path)) {
1577                         error << string_compose (_("Cannot parse plugin tag info from %1"), path) << endmsg;
1578                         return;
1579                 }
1580
1581                 for (XMLNodeConstIterator i = tree.root()->children().begin(); i != tree.root()->children().end(); ++i) {
1582                         PluginType type;
1583                         string id;
1584                         string tags;
1585                         string name;
1586                         bool user_set;
1587                         if (!(*i)->get_property (X_("type"), type) ||
1588                                         !(*i)->get_property (X_("id"), id) ||
1589                                         !(*i)->get_property (X_("tags"), tags) ||
1590                                         !(*i)->get_property (X_("name"), name)) {
1591                         }
1592                         if (!(*i)->get_property (X_("user-set"), user_set)) {
1593                                 user_set = false;
1594                         }
1595                         strip_whitespace_edges (tags);
1596                         set_tags (type, id, tags, name, user_set ? FromUserFile : FromFactoryFile );
1597                 }
1598         }
1599 }
1600
1601 void
1602 PluginManager::set_tags (PluginType t, string id, string tag, std::string name, TagType ttype )
1603 {
1604         string sanitized = sanitize_tag (tag);
1605
1606         PluginTag ps (to_generic_vst (t), id, sanitized, name, ttype );
1607         PluginTagList::const_iterator i = find (ptags.begin(), ptags.end(), ps);
1608         if (i == ptags.end()) {
1609                 ptags.insert (ps);
1610         } else if ( (uint32_t) ttype >=  (uint32_t) (*i).tagtype ) {  // only overwrite if we are more important than the existing. Gui > UserFile > FactoryFile > Plugin
1611                 ptags.erase (ps);
1612                 ptags.insert (ps);
1613         }
1614         if ( ttype == FromGui ) {
1615                 PluginTagChanged (t, id, sanitized); /* EMIT SIGNAL */
1616         }
1617 }
1618
1619 void
1620 PluginManager::reset_tags (PluginInfoPtr const& pi)
1621 {
1622         PluginTag ps (pi->type, pi->unique_id, pi->category, pi->name, FromPlug);
1623
1624         PluginTagList::const_iterator i = find (ptags.begin(), ptags.end(), ps);
1625         if (i != ptags.end()) {
1626                 ptags.erase (ps);
1627                 ptags.insert (ps);
1628         }
1629 }
1630
1631 std::string
1632 PluginManager::sanitize_tag (const std::string to_sanitize) const
1633 {
1634         if (to_sanitize.empty ()) {
1635                 return "";
1636         }
1637         string sanitized = to_sanitize;
1638         vector<string> tags;
1639         if (!PBD::tokenize (sanitized, string(" ,\n"), std::back_inserter (tags), true)) {
1640 #ifndef NDEBUG
1641                 cerr << _("PluginManager::sanitize_tag could not tokenize string: ") << sanitized << endmsg;
1642 #endif
1643                 return "";
1644         }
1645
1646         /* convert tokens to lower-case, space-separated list */
1647         sanitized = "";
1648         for (vector<string>::iterator t = tags.begin(); t != tags.end(); ++t) {
1649                 if (t != tags.begin ()) {
1650                         sanitized.append(" ");
1651                 }
1652                 sanitized.append (downcase (*t));
1653         }
1654
1655         return sanitized;
1656 }
1657
1658 std::vector<std::string>
1659 PluginManager::get_all_tags (TagFilter tag_filter) const
1660 {
1661         std::vector<std::string> ret;
1662
1663         PluginTagList::const_iterator pt;
1664         for (pt = ptags.begin(); pt != ptags.end(); ++pt) {
1665                 if ((*pt).tags.empty ()) {
1666                         continue;
1667                 }
1668
1669                 /* if favorites_only then we need to check the info ptr and maybe skip */
1670                 if (tag_filter == OnlyFavorites) {
1671                         PluginStatus stat ((*pt).type, (*pt).unique_id);
1672                         PluginStatusList::const_iterator i =  find (statuses.begin(), statuses.end(), stat);
1673                         if ((i != statuses.end()) && (i->status == Favorite)) {
1674                                 /* it's a favorite! */
1675                         } else {
1676                                 continue;
1677                         }
1678                 }
1679                 if (tag_filter == NoHidden) {
1680                         PluginStatus stat ((*pt).type, (*pt).unique_id);
1681                         PluginStatusList::const_iterator i =  find (statuses.begin(), statuses.end(), stat);
1682                         if ((i != statuses.end()) && (i->status == Hidden)) {
1683                                 continue;
1684                         }
1685                 }
1686
1687                 /* parse each plugin's tag string into separate tags */
1688                 vector<string> tags;
1689                 if (!PBD::tokenize ((*pt).tags, string(" "), std::back_inserter (tags), true)) {
1690 #ifndef NDEBUG
1691                         cerr << _("PluginManager: Could not tokenize string: ") << (*pt).tags << endmsg;
1692 #endif
1693                         continue;
1694                 }
1695
1696                 /* maybe add the tags we've found */
1697                 for (vector<string>::iterator t = tags.begin(); t != tags.end(); ++t) {
1698                         /* if this tag isn't already in the list, add it */
1699                         vector<string>::iterator i =  find (ret.begin(), ret.end(), *t);
1700                         if (i == ret.end()) {
1701                                 ret.push_back (*t);
1702                         }
1703                 }
1704         }
1705
1706         /* sort in alphabetical order */
1707         SortByTag sorter;
1708         sort (ret.begin(), ret.end(), sorter);
1709
1710         return ret;
1711 }
1712
1713
1714 const ARDOUR::PluginInfoList&
1715 PluginManager::windows_vst_plugin_info ()
1716 {
1717 #ifdef WINDOWS_VST_SUPPORT
1718         if (!_windows_vst_plugin_info) {
1719                 windows_vst_refresh ();
1720         }
1721         return *_windows_vst_plugin_info;
1722 #else
1723         return _empty_plugin_info;
1724 #endif
1725 }
1726
1727 const ARDOUR::PluginInfoList&
1728 PluginManager::mac_vst_plugin_info ()
1729 {
1730 #ifdef MACVST_SUPPORT
1731         assert(_mac_vst_plugin_info);
1732         return *_mac_vst_plugin_info;
1733 #else
1734         return _empty_plugin_info;
1735 #endif
1736 }
1737
1738 const ARDOUR::PluginInfoList&
1739 PluginManager::lxvst_plugin_info ()
1740 {
1741 #ifdef LXVST_SUPPORT
1742         assert(_lxvst_plugin_info);
1743         return *_lxvst_plugin_info;
1744 #else
1745         return _empty_plugin_info;
1746 #endif
1747 }
1748
1749 const ARDOUR::PluginInfoList&
1750 PluginManager::ladspa_plugin_info ()
1751 {
1752         assert(_ladspa_plugin_info);
1753         return *_ladspa_plugin_info;
1754 }
1755
1756 const ARDOUR::PluginInfoList&
1757 PluginManager::lv2_plugin_info ()
1758 {
1759 #ifdef LV2_SUPPORT
1760         assert(_lv2_plugin_info);
1761         return *_lv2_plugin_info;
1762 #else
1763         return _empty_plugin_info;
1764 #endif
1765 }
1766
1767 const ARDOUR::PluginInfoList&
1768 PluginManager::au_plugin_info ()
1769 {
1770 #ifdef AUDIOUNIT_SUPPORT
1771         if (_au_plugin_info) {
1772                 return *_au_plugin_info;
1773         }
1774 #endif
1775         return _empty_plugin_info;
1776 }
1777
1778 const ARDOUR::PluginInfoList&
1779 PluginManager::lua_plugin_info ()
1780 {
1781         assert(_lua_plugin_info);
1782         return *_lua_plugin_info;
1783 }