ardour
plugin_manager.cc
Go to the documentation of this file.
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"
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"
60 #include "ardour/ladspa.h"
61 #include "ardour/ladspa_plugin.h"
62 #include "ardour/plugin.h"
63 #include "ardour/plugin_manager.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
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 
97 std::string PluginManager::scanner_bin_path = "";
98 
101 {
102  if (!_instance) {
103  _instance = new PluginManager;
104  }
105  return *_instance;
106 }
107 
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);
163 #ifdef WINDOWS_VST_SUPPORT
164  if (Config->get_use_windows_vst ()) {
166  }
167 #endif /* WINDOWS_VST_SUPPORT */
168 
169 #ifdef LXVST_SUPPORT
170  if (Config->get_use_lxvst()) {
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) {
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 
214 {
215  if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) {
216  // don't bother, just exit quickly.
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
264 {
265  _cancel_scan = true;
266 }
267 
268 void
270 {
271  _cancel_timeout = true;
272 }
273 
274 void
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
312 {
313 #ifdef WINDOWS_VST_SUPPORT
314  {
315  vector<string> fsi_files;
316  find_files_matching_regex (fsi_files, Config->get_plugin_path_vst(), "\\.fsb$", 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(), "\\.fsb$", 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, "\\.fsb$", /* 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
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
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
371 {
372  if (_ladspa_plugin_info) {
373  _ladspa_plugin_info->clear ();
374  } else {
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
411 {
412  add_presets ("ladspa");
413 }
414 
415 void
417 {
418  add_presets ("windows-vst");
419 }
420 
421 void
423 {
424  add_presets ("lxvst");
425 }
426 
427 void
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
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;
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 
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
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
630 {
631  DEBUG_TRACE (DEBUG::PluginManager, "LV2: refresh\n");
632  delete _lv2_plugin_info;
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;
647 
648  // disable automatic scan in case we crash
649  Config->set_discover_audio_units (false);
650  Config->save_state();
651 
652  /* note: AU require a CAComponentDescription pointer provided by the OS.
653  * Ardour only caches port and i/o config. It can't just 'scan' without
654  * 'discovering' (like we do for VST).
655  *
656  * So in case discovery fails, we assume the worst: the Description
657  * is broken (malicious plugins) and even a simple 'scan' would always
658  * crash ardour on startup. Hence we disable Auto-Scan on start.
659  *
660  * If the crash happens at any later time (description is available),
661  * Ardour will blacklist the plugin in question -- unless
662  * the crash happens during realtime-run.
663  */
664 
665  // successful scan re-enabled automatic discovery
666  Config->set_discover_audio_units (true);
667  Config->save_state();
668 }
669 
670 #endif
671 
672 #ifdef WINDOWS_VST_SUPPORT
673 
674 void
675 PluginManager::windows_vst_refresh (bool cache_only)
676 {
678  _windows_vst_plugin_info->clear ();
679  } else {
681  }
682 
683  windows_vst_discover_from_path (Config->get_plugin_path_vst(), cache_only);
684 }
685 
686 static bool windows_vst_filter (const string& str, void * /*arg*/)
687 {
688  /* Not a dotfile, has a prefix before a period, suffix is "dll" */
689  return str[0] != '.' && str.length() > 4 && strings_equal_ignore_case (".dll", str.substr(str.length() - 4));
690 }
691 
692 int
693 PluginManager::windows_vst_discover_from_path (string path, bool cache_only)
694 {
695  vector<string> plugin_objects;
696  vector<string>::iterator x;
697  int ret = 0;
698 
699  DEBUG_TRACE (DEBUG::PluginManager, string_compose ("detecting Windows VST plugins along %1\n", path));
700 
701  find_files_matching_filter (plugin_objects, Config->get_plugin_path_vst(), windows_vst_filter, 0, false, true, true);
702 
703  for (x = plugin_objects.begin(); x != plugin_objects.end (); ++x) {
704  ARDOUR::PluginScanMessage(_("VST"), *x, !cache_only && !cancelled());
705  windows_vst_discover (*x, cache_only || cancelled());
706  }
707 
708  return ret;
709 }
710 
711 int
712 PluginManager::windows_vst_discover (string path, bool cache_only)
713 {
714  DEBUG_TRACE (DEBUG::PluginManager, string_compose ("windows_vst_discover '%1'\n", path));
715 
716  _cancel_timeout = false;
717  vector<VSTInfo*> * finfos = vstfx_get_info_fst (const_cast<char *> (path.c_str()),
718  cache_only ? VST_SCAN_CACHE_ONLY : VST_SCAN_USE_APP);
719 
720  if (finfos->empty()) {
721  DEBUG_TRACE (DEBUG::PluginManager, string_compose ("Cannot get Windows VST information from '%1'\n", path));
722  return -1;
723  }
724 
725  uint32_t discovered = 0;
726  for (vector<VSTInfo *>::iterator x = finfos->begin(); x != finfos->end(); ++x) {
727  VSTInfo* finfo = *x;
728  char buf[32];
729 
730  if (!finfo->canProcessReplacing) {
731  warning << string_compose (_("VST plugin %1 does not support processReplacing, and so cannot be used in %2 at this time"),
732  finfo->name, PROGRAM_NAME)
733  << endl;
734  continue;
735  }
736 
738 
739  /* what a joke freeware VST is */
740 
741  if (!strcasecmp ("The Unnamed plugin", finfo->name)) {
742  info->name = PBD::basename_nosuffix (path);
743  } else {
744  info->name = finfo->name;
745  }
746 
747 
748  snprintf (buf, sizeof (buf), "%d", finfo->UniqueID);
749  info->unique_id = buf;
750  info->category = "VST";
751  info->path = path;
752  info->creator = finfo->creator;
753  info->index = 0;
754  info->n_inputs.set_audio (finfo->numInputs);
755  info->n_outputs.set_audio (finfo->numOutputs);
756  info->n_inputs.set_midi ((finfo->wantMidi&1) ? 1 : 0);
757  info->n_outputs.set_midi ((finfo->wantMidi&2) ? 1 : 0);
758  info->type = ARDOUR::Windows_VST;
759 
760  // TODO: check dup-IDs (lxvst AND windows vst)
761  bool duplicate = false;
762 
763  if (!_windows_vst_plugin_info->empty()) {
764  for (PluginInfoList::iterator i =_windows_vst_plugin_info->begin(); i != _windows_vst_plugin_info->end(); ++i) {
765  if ((info->type == (*i)->type)&&(info->unique_id == (*i)->unique_id)) {
766  warning << "Ignoring duplicate Windows VST plugin " << info->name << "\n";
767  duplicate = true;
768  break;
769  }
770  }
771  }
772 
773  if (!duplicate) {
774  DEBUG_TRACE (DEBUG::PluginManager, string_compose ("Windows VST plugin ID '%1'\n", info->unique_id));
775  _windows_vst_plugin_info->push_back (info);
776  discovered++;
777  }
778  }
779 
780  vstfx_free_info_list (finfos);
781  return discovered > 0 ? 0 : -1;
782 }
783 
784 #endif // WINDOWS_VST_SUPPORT
785 
786 #ifdef LXVST_SUPPORT
787 
788 void
789 PluginManager::lxvst_refresh (bool cache_only)
790 {
791  if (_lxvst_plugin_info) {
792  _lxvst_plugin_info->clear ();
793  } else {
795  }
796 
797  lxvst_discover_from_path (Config->get_plugin_path_lxvst(), cache_only);
798 }
799 
800 static bool lxvst_filter (const string& str, void *)
801 {
802  /* Not a dotfile, has a prefix before a period, suffix is "so" */
803 
804  return str[0] != '.' && (str.length() > 3 && str.find (".so") == (str.length() - 3));
805 }
806 
807 int
808 PluginManager::lxvst_discover_from_path (string path, bool cache_only)
809 {
810  vector<string> plugin_objects;
811  vector<string>::iterator x;
812  int ret = 0;
813 
814 #ifndef NDEBUG
815  (void) path;
816 #endif
817 
818  DEBUG_TRACE (DEBUG::PluginManager, string_compose ("Discovering linuxVST plugins along %1\n", path));
819 
820  find_files_matching_filter (plugin_objects, Config->get_plugin_path_lxvst(), lxvst_filter, 0, false, true, true);
821 
822  for (x = plugin_objects.begin(); x != plugin_objects.end (); ++x) {
823  ARDOUR::PluginScanMessage(_("LXVST"), *x, !cache_only && !cancelled());
824  lxvst_discover (*x, cache_only || cancelled());
825  }
826 
827  return ret;
828 }
829 
830 int
831 PluginManager::lxvst_discover (string path, bool cache_only)
832 {
833  DEBUG_TRACE (DEBUG::PluginManager, string_compose ("checking apparent LXVST plugin at %1\n", path));
834 
835  _cancel_timeout = false;
836  vector<VSTInfo*> * finfos = vstfx_get_info_lx (const_cast<char *> (path.c_str()),
837  cache_only ? VST_SCAN_CACHE_ONLY : VST_SCAN_USE_APP);
838 
839  if (finfos->empty()) {
840  DEBUG_TRACE (DEBUG::PluginManager, string_compose ("Cannot get Linux VST information from '%1'\n", path));
841  return -1;
842  }
843 
844  uint32_t discovered = 0;
845  for (vector<VSTInfo *>::iterator x = finfos->begin(); x != finfos->end(); ++x) {
846  VSTInfo* finfo = *x;
847  char buf[32];
848 
849  if (!finfo->canProcessReplacing) {
850  warning << string_compose (_("linuxVST plugin %1 does not support processReplacing, and so cannot be used in %2 at this time"),
851  finfo->name, PROGRAM_NAME)
852  << endl;
853  continue;
854  }
855 
857 
858  if (!strcasecmp ("The Unnamed plugin", finfo->name)) {
859  info->name = PBD::basename_nosuffix (path);
860  } else {
861  info->name = finfo->name;
862  }
863 
864 
865  snprintf (buf, sizeof (buf), "%d", finfo->UniqueID);
866  info->unique_id = buf;
867  info->category = "linuxVSTs";
868  info->path = path;
869  info->creator = finfo->creator;
870  info->index = 0;
871  info->n_inputs.set_audio (finfo->numInputs);
872  info->n_outputs.set_audio (finfo->numOutputs);
873  info->n_inputs.set_midi ((finfo->wantMidi&1) ? 1 : 0);
874  info->n_outputs.set_midi ((finfo->wantMidi&2) ? 1 : 0);
875  info->type = ARDOUR::LXVST;
876 
877  /* Make sure we don't find the same plugin in more than one place along
878  the LXVST_PATH We can't use a simple 'find' because the path is included
879  in the PluginInfo, and that is the one thing we can be sure MUST be
880  different if a duplicate instance is found. So we just compare the type
881  and unique ID (which for some VSTs isn't actually unique...)
882  */
883 
884  // TODO: check dup-IDs with windowsVST, too
885  bool duplicate = false;
886  if (!_lxvst_plugin_info->empty()) {
887  for (PluginInfoList::iterator i =_lxvst_plugin_info->begin(); i != _lxvst_plugin_info->end(); ++i) {
888  if ((info->type == (*i)->type)&&(info->unique_id == (*i)->unique_id)) {
889  warning << "Ignoring duplicate Linux VST plugin " << info->name << "\n";
890  duplicate = true;
891  break;
892  }
893  }
894  }
895 
896  if (!duplicate) {
897  _lxvst_plugin_info->push_back (info);
898  discovered++;
899  }
900  }
901 
902  vstfx_free_info_list (finfos);
903  return discovered > 0 ? 0 : -1;
904 }
905 
906 #endif // LXVST_SUPPORT
907 
908 
911 {
912  PluginStatus ps (pi->type, pi->unique_id);
913  PluginStatusList::const_iterator i = find (statuses.begin(), statuses.end(), ps);
914  if (i == statuses.end() ) {
915  return Normal;
916  } else {
917  return i->status;
918  }
919 }
920 
921 void
923 {
924  ofstream ofs;
925  std::string path = Glib::build_filename (user_config_directory(), "plugin_statuses");
926 
927  ofs.open (path.c_str(), ios_base::openmode (ios::out|ios::trunc));
928 
929  if (!ofs) {
930  return;
931  }
932 
933  for (PluginStatusList::iterator i = statuses.begin(); i != statuses.end(); ++i) {
934  switch ((*i).type) {
935  case LADSPA:
936  ofs << "LADSPA";
937  break;
938  case AudioUnit:
939  ofs << "AudioUnit";
940  break;
941  case LV2:
942  ofs << "LV2";
943  break;
944  case Windows_VST:
945  ofs << "Windows-VST";
946  break;
947  case LXVST:
948  ofs << "LXVST";
949  break;
950  }
951 
952  ofs << ' ';
953 
954  switch ((*i).status) {
955  case Normal:
956  ofs << "Normal";
957  break;
958  case Favorite:
959  ofs << "Favorite";
960  break;
961  case Hidden:
962  ofs << "Hidden";
963  break;
964  }
965 
966  ofs << ' ';
967  ofs << (*i).unique_id;;
968  ofs << endl;
969  }
970 
971  ofs.close ();
972 }
973 
974 void
976 {
977  std::string path = Glib::build_filename (user_config_directory(), "plugin_statuses");
978  ifstream ifs (path.c_str());
979 
980  if (!ifs) {
981  return;
982  }
983 
984  std::string stype;
985  std::string sstatus;
986  std::string id;
987  PluginType type;
988  PluginStatusType status;
989  char buf[1024];
990 
991  while (ifs) {
992 
993  ifs >> stype;
994  if (!ifs) {
995  break;
996 
997  }
998 
999  ifs >> sstatus;
1000  if (!ifs) {
1001  break;
1002 
1003  }
1004 
1005  /* rest of the line is the plugin ID */
1006 
1007  ifs.getline (buf, sizeof (buf), '\n');
1008  if (!ifs) {
1009  break;
1010  }
1011 
1012  if (sstatus == "Normal") {
1013  status = Normal;
1014  } else if (sstatus == "Favorite") {
1015  status = Favorite;
1016  } else if (sstatus == "Hidden") {
1017  status = Hidden;
1018  } else {
1019  error << string_compose (_("unknown plugin status type \"%1\" - all entries ignored"), sstatus)
1020  << endmsg;
1021  statuses.clear ();
1022  break;
1023  }
1024 
1025  if (stype == "LADSPA") {
1026  type = LADSPA;
1027  } else if (stype == "AudioUnit") {
1028  type = AudioUnit;
1029  } else if (stype == "LV2") {
1030  type = LV2;
1031  } else if (stype == "Windows-VST") {
1032  type = Windows_VST;
1033  } else if (stype == "LXVST") {
1034  type = LXVST;
1035  } else {
1036  error << string_compose (_("unknown plugin type \"%1\" - ignored"), stype)
1037  << endmsg;
1038  continue;
1039  }
1040 
1041  id = buf;
1043  set_status (type, id, status);
1044  }
1045 
1046  ifs.close ();
1047 }
1048 
1049 void
1051 {
1052  PluginStatus ps (t, id, status);
1053  statuses.erase (ps);
1054 
1055  if (status == Normal) {
1056  return;
1057  }
1058 
1059  statuses.insert (ps);
1060 }
1061 
1064 {
1065 #ifdef WINDOWS_VST_SUPPORT
1066  if (!_windows_vst_plugin_info) {
1068  }
1069  return *_windows_vst_plugin_info;
1070 #else
1071  return _empty_plugin_info;
1072 #endif
1073 }
1074 
1077 {
1078 #ifdef LXVST_SUPPORT
1079  assert(_lxvst_plugin_info);
1080  return *_lxvst_plugin_info;
1081 #else
1082  return _empty_plugin_info;
1083 #endif
1084 }
1085 
1088 {
1089  assert(_ladspa_plugin_info);
1090  return *_ladspa_plugin_info;
1091 }
1092 
1095 {
1096 #ifdef LV2_SUPPORT
1097  assert(_lv2_plugin_info);
1098  return *_lv2_plugin_info;
1099 #else
1100  return _empty_plugin_info;
1101 #endif
1102 }
1103 
1106 {
1107 #ifdef AUDIOUNIT_SUPPORT
1108  if (_au_plugin_info) {
1109  return *_au_plugin_info;
1110  }
1111 #endif
1112  return _empty_plugin_info;
1113 }
std::string category
Definition: plugin.h:60
std::string to_string(T t, std::ios_base &(*f)(std::ios_base &))
Definition: convert.h:53
const LADSPA_Descriptor *(* LADSPA_Descriptor_Function)(unsigned long Index)
Definition: ladspa.h:596
ARDOUR::PluginInfoList * _au_plugin_info
int ladspa_discover(std::string path)
LIBARDOUR_API void vstfx_free_info_list(std::vector< VSTInfo * > *infos)
bool strings_equal_ignore_case(const string &a, const string &b)
Definition: convert.cc:273
LIBARDOUR_API PBD::Searchpath ladspa_search_path()
Definition: search_paths.cc:89
int UniqueID
Definition: vst_types.h:41
void windows_vst_refresh(bool cache_only=false)
LIBARDOUR_API std::string get_personal_vst_blacklist_dir()
int numOutputs
Definition: vst_types.h:45
#define DEBUG(format,...)
void find_files_matching_regex(vector< string > &result, const Searchpath &paths, const std::string &regexp, bool recurse)
Definition: file_utils.cc:226
std::string path
Definition: plugin.h:62
ARDOUR::PluginInfoList & windows_vst_plugin_info()
PluginStatusList statuses
ARDOUR::PluginInfoList * _windows_vst_plugin_info
uint32_t n_audio() const
Definition: chan_count.h:63
void set_status(ARDOUR::PluginType type, std::string unique_id, PluginStatusType status)
Definition: Beats.hpp:239
void lxvst_refresh(bool cache_only=false)
LIBPBD_API Transmitter error
LIBPBD_API Transmitter warning
int windows_vst_discover_from_path(std::string path, bool cache_only=false)
const char * Name
Definition: ladspa.h:396
std::ostream & endmsg(std::ostream &ostr)
Definition: transmitter.h:71
static PluginInfoList * discover()
Definition: lv2_plugin.cc:2455
unsigned long PortCount
Definition: ladspa.h:409
LIBPBD_API void strip_whitespace_edges(std::string &str)
ARDOUR::PluginInfoList & lv2_plugin_info()
bool find_file(const Searchpath &search_path, const string &filename, std::string &result)
Definition: file_utils.cc:187
int wantMidi
Definition: vst_types.h:48
ARDOUR::PluginInfoList * _lv2_plugin_info
#define _(Text)
Definition: i18n.h:11
LIBARDOUR_API const char * vst_search_path()
unsigned long UniqueID
Definition: ladspa.h:382
ARDOUR::PluginInfoList _empty_plugin_info
ChanCount n_outputs
Definition: plugin.h:64
LIBARDOUR_API std::string user_config_directory(int version=-1)
const std::string get_default_windows_vst_path() const
LIBARDOUR_API uint64_t PluginManager
Definition: plugin.h:85
#define X_(Text)
Definition: i18n.h:13
void find_files_matching_pattern(vector< string > &result, const Searchpath &paths, const Glib::PatternSpec &pattern)
Definition: file_utils.cc:168
PBD::Signal0< void > PluginListChanged
LIBARDOUR_API RCConfiguration * Config
Definition: globals.cc:119
int numInputs
Definition: vst_types.h:44
static PluginManager * _instance
ARDOUR::PluginInfoList & ladspa_plugin_info()
void au_refresh(bool cache_only=false)
std::string windows_vst_path
Definition: amp.h:29
LIBARDOUR_API std::string ardour_dll_directory()
char * name
Definition: vst_types.h:39
#define DEBUG_TRACE(bits, str)
Definition: debug.h:55
LIBARDOUR_API std::string user_cache_directory()
LIBPBD_API Transmitter info
void set_audio(uint32_t a)
Definition: chan_count.h:64
static std::string scanner_bin_path
int lxvst_discover(std::string path, bool cache_only=false)
ChanCount n_inputs
Definition: plugin.h:63
std::string unique_id
Definition: plugin.h:67
ARDOUR::PluginInfoList & au_plugin_info()
LIBPBD_API Glib::ustring basename_nosuffix(Glib::ustring)
#define LADSPA_IS_PORT_AUDIO(x)
Definition: ladspa.h:173
static PluginManager & instance()
std::vector< uint32_t > ladspa_plugin_whitelist
ARDOUR::PluginInfoList & lxvst_plugin_info()
ARDOUR::PluginInfoList * _ladspa_plugin_info
ARDOUR::PluginInfoList * _lxvst_plugin_info
#define LADSPA_IS_PORT_INPUT(x)
Definition: ladspa.h:170
Definition: editor.h:86
LIBARDOUR_API PBD::Signal1< void, std::string > BootMessage
Definition: globals.cc:135
LIBPBD_TEMPLATE_MEMBER_API const std::string to_string() const
Definition: search_path.cc:99
Definition: debug.h:30
std::string creator
Definition: plugin.h:61
std::string get_ladspa_category(uint32_t id)
LIBARDOUR_API std::string get_personal_vst_info_cache_dir()
int canProcessReplacing
Definition: vst_types.h:51
const LADSPA_PortDescriptor * PortDescriptors
Definition: ladspa.h:413
void add_presets(std::string domain)
LIBARDOUR_API PBD::Signal3< void, std::string, std::string, bool > PluginScanMessage
Definition: globals.cc:136
std::list< PluginInfoPtr > PluginInfoList
Definition: plugin.h:90
#define LADSPA_IS_PORT_OUTPUT(x)
Definition: ladspa.h:171
int windows_vst_discover(std::string path, bool cache_only=false)
char * creator
Definition: vst_types.h:40
void find_files_matching_filter(vector< string > &result, const Searchpath &paths, bool(*filter)(const string &, void *), void *arg, bool pass_fullpath, bool return_fullpath, bool recurse)
Definition: file_utils.cc:271
int lxvst_discover_from_path(std::string path, bool cache_only=false)
void add_lrdf_data(const std::string &path)
const std::string get_default_lxvst_path() const
ARDOUR::PluginType type
Definition: plugin.h:65
std::string name
Definition: plugin.h:59
static PluginInfoList * discover()
Definition: audio_unit.cc:2280
std::string string_compose(const std::string &fmt, const T1 &o1)
Definition: compose.h:208
uint32_t index
Definition: plugin.h:86
const char * Maker
Definition: ladspa.h:400
PluginStatusType get_status(const PluginInfoPtr &)
void refresh(bool cache_only=false)