2 Copyright (C) 2000-2006 Paul Davis
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.
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.
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.
21 #include "libardour-config.h"
26 #include <sys/types.h>
35 #ifdef WINDOWS_VST_SUPPORT
37 #include "pbd/basename.h"
39 #endif // WINDOWS_VST_SUPPORT
42 #include "ardour/linux_vst_support.h"
43 #include "pbd/basename.h"
45 #endif //LXVST_SUPPORT
47 #include <glibmm/miscutils.h>
48 #include <glibmm/pattern.h>
50 #include "pbd/pathscanner.h"
51 #include "pbd/whitespace.h"
52 #include "pbd/file_utils.h"
54 #include "ardour/debug.h"
55 #include "ardour/filesystem_paths.h"
56 #include "ardour/ladspa.h"
57 #include "ardour/ladspa_plugin.h"
58 #include "ardour/plugin.h"
59 #include "ardour/plugin_manager.h"
60 #include "ardour/rc_configuration.h"
62 #include "ardour/ladspa_search_path.h"
65 #include "ardour/lv2_plugin.h"
68 #ifdef WINDOWS_VST_SUPPORT
69 #include "ardour/windows_vst_plugin.h"
73 #include "ardour/lxvst_plugin.h"
76 #ifdef AUDIOUNIT_SUPPORT
77 #include "ardour/audio_unit.h"
78 #include <Carbon/Carbon.h>
81 #include "pbd/error.h"
82 #include "pbd/stl_delete.h"
86 #include "ardour/debug.h"
88 using namespace ARDOUR;
92 PluginManager* PluginManager::_instance = 0;
95 PluginManager::instance()
98 _instance = new PluginManager;
103 PluginManager::PluginManager ()
104 : _windows_vst_plugin_info(0)
105 , _lxvst_plugin_info(0)
106 , _ladspa_plugin_info(0)
107 , _lv2_plugin_info(0)
115 if ((s = getenv ("LADSPA_RDF_PATH"))){
119 if (lrdf_path.length() == 0) {
120 lrdf_path = "/usr/local/share/ladspa/rdf:/usr/share/ladspa/rdf";
123 add_lrdf_data(lrdf_path);
124 add_ladspa_presets();
125 #ifdef WINDOWS_VST_SUPPORT
126 if (Config->get_use_windows_vst ()) {
127 add_windows_vst_presets ();
129 #endif /* WINDOWS_VST_SUPPORT */
132 if (Config->get_use_lxvst()) {
135 #endif /* Native LinuxVST support*/
137 if ((s = getenv ("VST_PATH"))) {
138 windows_vst_path = s;
139 } else if ((s = getenv ("VST_PLUGINS"))) {
140 windows_vst_path = s;
143 if ((s = getenv ("LXVST_PATH"))) {
145 } else if ((s = getenv ("LXVST_PLUGINS"))) {
149 if (_instance == 0) {
153 /* the plugin manager is constructed too early to use Profile */
155 if (getenv ("ARDOUR_SAE")) {
156 ladspa_plugin_whitelist.push_back (1203); // single band parametric
157 ladspa_plugin_whitelist.push_back (1772); // caps compressor
158 ladspa_plugin_whitelist.push_back (1913); // fast lookahead limiter
159 ladspa_plugin_whitelist.push_back (1075); // simple RMS expander
160 ladspa_plugin_whitelist.push_back (1061); // feedback delay line (max 5s)
161 ladspa_plugin_whitelist.push_back (1216); // gverb
162 ladspa_plugin_whitelist.push_back (2150); // tap pitch shifter
165 BootMessage (_("Discovering Plugins"));
169 PluginManager::~PluginManager()
175 PluginManager::refresh ()
177 DEBUG_TRACE (DEBUG::PluginManager, "PluginManager::refresh\n");
183 #ifdef WINDOWS_VST_SUPPORT
184 if (Config->get_use_windows_vst()) {
185 windows_vst_refresh ();
187 #endif // WINDOWS_VST_SUPPORT
190 if(Config->get_use_lxvst()) {
193 #endif //Native linuxVST SUPPORT
195 #ifdef AUDIOUNIT_SUPPORT
199 PluginListChanged (); /* EMIT SIGNAL */
203 PluginManager::ladspa_refresh ()
205 if (_ladspa_plugin_info) {
206 _ladspa_plugin_info->clear ();
208 _ladspa_plugin_info = new ARDOUR::PluginInfoList ();
211 /* allow LADSPA_PATH to augment, not override standard locations */
213 /* Only add standard locations to ladspa_path if it doesn't
214 * already contain them. Check for trailing G_DIR_SEPARATOR too.
217 vector<string> ladspa_modules;
219 DEBUG_TRACE (DEBUG::PluginManager, string_compose ("LADSPA: search along: [%1]\n", ladspa_search_path().to_string()));
221 Glib::PatternSpec so_extension_pattern("*.so");
222 Glib::PatternSpec dylib_extension_pattern("*.dylib");
223 Glib::PatternSpec dll_extension_pattern("*.dll");
225 find_matching_files_in_search_path (ladspa_search_path (),
226 so_extension_pattern, ladspa_modules);
228 find_matching_files_in_search_path (ladspa_search_path (),
229 dylib_extension_pattern, ladspa_modules);
231 find_matching_files_in_search_path (ladspa_search_path (),
232 dll_extension_pattern, ladspa_modules);
234 for (vector<std::string>::iterator i = ladspa_modules.begin(); i != ladspa_modules.end(); ++i) {
235 ladspa_discover (*i);
239 static bool rdf_filter (const string &str, void* /*arg*/)
241 return str[0] != '.' &&
242 ((str.find(".rdf") == (str.length() - 4)) ||
243 (str.find(".rdfs") == (str.length() - 5)) ||
244 (str.find(".n3") == (str.length() - 3)) ||
245 (str.find(".ttl") == (str.length() - 4)));
249 PluginManager::add_ladspa_presets()
251 add_presets ("ladspa");
255 PluginManager::add_windows_vst_presets()
257 add_presets ("windows-vst");
261 PluginManager::add_lxvst_presets()
263 add_presets ("lxvst");
267 PluginManager::add_presets(string domain)
271 vector<string *> *presets;
272 vector<string *>::iterator x;
275 if ((envvar = getenv ("HOME")) == 0) {
279 string path = string_compose("%1/.%2/rdf", envvar, domain);
280 presets = scanner (path, rdf_filter, 0, false, true);
283 for (x = presets->begin(); x != presets->end (); ++x) {
284 string file = "file:" + **x;
285 if (lrdf_read_file(file.c_str())) {
286 warning << string_compose(_("Could not parse rdf file: %1"), *x) << endmsg;
290 vector_delete (presets);
296 PluginManager::add_lrdf_data (const string &path)
300 vector<string *>* rdf_files;
301 vector<string *>::iterator x;
303 rdf_files = scanner (path, rdf_filter, 0, false, true);
306 for (x = rdf_files->begin(); x != rdf_files->end (); ++x) {
307 const string uri(string("file://") + **x);
309 if (lrdf_read_file(uri.c_str())) {
310 warning << "Could not parse rdf file: " << uri << endmsg;
314 vector_delete (rdf_files);
320 PluginManager::ladspa_discover (string path)
322 DEBUG_TRACE (DEBUG::PluginManager, string_compose ("Checking for LADSPA plugin at %1\n", path));
324 Glib::Module module(path);
325 const LADSPA_Descriptor *descriptor;
326 LADSPA_Descriptor_Function dfunc;
330 error << string_compose(_("LADSPA: cannot load module \"%1\" (%2)"),
331 path, Glib::Module::get_last_error()) << endmsg;
336 if (!module.get_symbol("ladspa_descriptor", func)) {
337 error << string_compose(_("LADSPA: module \"%1\" has no descriptor function."), path) << endmsg;
338 error << Glib::Module::get_last_error() << endmsg;
342 dfunc = (LADSPA_Descriptor_Function)func;
344 DEBUG_TRACE (DEBUG::PluginManager, string_compose ("LADSPA plugin found at %1\n", path));
346 for (uint32_t i = 0; ; ++i) {
347 if ((descriptor = dfunc (i)) == 0) {
351 if (!ladspa_plugin_whitelist.empty()) {
352 if (find (ladspa_plugin_whitelist.begin(), ladspa_plugin_whitelist.end(), descriptor->UniqueID) == ladspa_plugin_whitelist.end()) {
357 PluginInfoPtr info(new LadspaPluginInfo);
358 info->name = descriptor->Name;
359 info->category = get_ladspa_category(descriptor->UniqueID);
360 info->creator = descriptor->Maker;
363 info->n_inputs = ChanCount();
364 info->n_outputs = ChanCount();
365 info->type = ARDOUR::LADSPA;
368 snprintf (buf, sizeof (buf), "%lu", descriptor->UniqueID);
369 info->unique_id = buf;
371 for (uint32_t n=0; n < descriptor->PortCount; ++n) {
372 if ( LADSPA_IS_PORT_AUDIO (descriptor->PortDescriptors[n]) ) {
373 if ( LADSPA_IS_PORT_INPUT (descriptor->PortDescriptors[n]) ) {
374 info->n_inputs.set_audio(info->n_inputs.n_audio() + 1);
376 else if ( LADSPA_IS_PORT_OUTPUT (descriptor->PortDescriptors[n]) ) {
377 info->n_outputs.set_audio(info->n_outputs.n_audio() + 1);
382 if(_ladspa_plugin_info->empty()){
383 _ladspa_plugin_info->push_back (info);
386 //Ensure that the plugin is not already in the plugin list.
390 for (PluginInfoList::const_iterator i = _ladspa_plugin_info->begin(); i != _ladspa_plugin_info->end(); ++i) {
391 if(0 == info->unique_id.compare((*i)->unique_id)){
397 _ladspa_plugin_info->push_back (info);
400 DEBUG_TRACE (DEBUG::PluginManager, string_compose ("Found LADSPA plugin, name: %1, Inputs: %2, Outputs: %3\n", info->name, info->n_inputs, info->n_outputs));
403 // GDB WILL NOT LIKE YOU IF YOU DO THIS
410 PluginManager::get_ladspa_category (uint32_t plugin_id)
414 lrdf_statement pattern;
416 snprintf(buf, sizeof(buf), "%s%" PRIu32, LADSPA_BASE, plugin_id);
417 pattern.subject = buf;
418 pattern.predicate = const_cast<char*>(RDF_TYPE);
420 pattern.object_type = lrdf_uri;
422 lrdf_statement* matches1 = lrdf_matches (&pattern);
428 pattern.subject = matches1->object;
429 pattern.predicate = const_cast<char*>(LADSPA_BASE "hasLabel");
431 pattern.object_type = lrdf_literal;
433 lrdf_statement* matches2 = lrdf_matches (&pattern);
434 lrdf_free_statements(matches1);
440 string label = matches2->object;
441 lrdf_free_statements(matches2);
443 /* Kludge LADSPA class names to be singular and match LV2 class names.
444 This avoids duplicate plugin menus for every class, which is necessary
445 to make the plugin category menu at all usable, but is obviously a
448 In the short term, lrdf could be updated so the labels match and a new
449 release made. To support both specs, we should probably be mapping the
450 URIs to the same category in code and perhaps tweaking that hierarchy
451 dynamically to suit the user. Personally, I (drobilla) think that time
452 is better spent replacing the little-used LRDF.
454 In the longer term, we will abandon LRDF entirely in favour of LV2 and
455 use that class hierarchy. Aside from fixing this problem properly, that
456 will also allow for translated labels. SWH plugins have been LV2 for
457 ages; TAP needs porting. I don't know of anything else with LRDF data.
459 if (label == "Utilities") {
461 } else if (label == "Pitch shifters") {
462 return "Pitch Shifter";
463 } else if (label != "Dynamics" && label != "Chorus"
464 &&label[label.length() - 1] == 's'
465 && label[label.length() - 2] != 's') {
466 return label.substr(0, label.length() - 1);
477 PluginManager::lv2_refresh ()
479 DEBUG_TRACE (DEBUG::PluginManager, "LV2: refresh\n");
480 delete _lv2_plugin_info;
481 _lv2_plugin_info = LV2PluginInfo::discover();
485 #ifdef AUDIOUNIT_SUPPORT
487 PluginManager::au_refresh ()
489 DEBUG_TRACE (DEBUG::PluginManager, "AU: refresh\n");
490 delete _au_plugin_info;
491 _au_plugin_info = AUPluginInfo::discover();
496 #ifdef WINDOWS_VST_SUPPORT
499 PluginManager::windows_vst_refresh ()
501 if (_windows_vst_plugin_info) {
502 _windows_vst_plugin_info->clear ();
504 _windows_vst_plugin_info = new ARDOUR::PluginInfoList();
507 if (windows_vst_path.length() == 0) {
508 windows_vst_path = "/usr/local/lib/vst:/usr/lib/vst";
511 windows_vst_discover_from_path (windows_vst_path);
515 PluginManager::add_windows_vst_directory (string path)
517 if (windows_vst_discover_from_path (path) == 0) {
518 windows_vst_path += ':';
519 windows_vst_path += path;
525 static bool windows_vst_filter (const string& str, void *arg)
527 /* Not a dotfile, has a prefix before a period, suffix is "dll" */
529 return str[0] != '.' && (str.length() > 4 && str.find (".dll") == (str.length() - 4));
533 PluginManager::windows_vst_discover_from_path (string path)
536 vector<string *> *plugin_objects;
537 vector<string *>::iterator x;
540 DEBUG_TRACE (DEBUG::PluginManager, string_compose ("detecting Windows VST plugins along %1\n", path));
542 plugin_objects = scanner (windows_vst_path, windows_vst_filter, 0, false, true);
544 if (plugin_objects) {
545 for (x = plugin_objects->begin(); x != plugin_objects->end (); ++x) {
546 windows_vst_discover (**x);
549 vector_delete (plugin_objects);
556 PluginManager::windows_vst_discover (string path)
561 if ((finfo = fst_get_info (const_cast<char *> (path.c_str()))) == 0) {
562 warning << "Cannot get Windows VST information from " << path << endmsg;
566 if (!finfo->canProcessReplacing) {
567 warning << string_compose (_("VST plugin %1 does not support processReplacing, and so cannot be used in %2 at this time"),
568 finfo->name, PROGRAM_NAME)
572 PluginInfoPtr info (new WindowsVSTPluginInfo);
574 /* what a joke freeware VST is */
576 if (!strcasecmp ("The Unnamed plugin", finfo->name)) {
577 info->name = PBD::basename_nosuffix (path);
579 info->name = finfo->name;
583 snprintf (buf, sizeof (buf), "%d", finfo->UniqueID);
584 info->unique_id = buf;
585 info->category = "VST";
587 info->creator = finfo->creator;
589 info->n_inputs.set_audio (finfo->numInputs);
590 info->n_outputs.set_audio (finfo->numOutputs);
591 info->n_inputs.set_midi (finfo->wantMidi ? 1 : 0);
592 info->type = ARDOUR::Windows_VST;
594 _windows_vst_plugin_info->push_back (info);
595 fst_free_info (finfo);
600 #endif // WINDOWS_VST_SUPPORT
605 PluginManager::lxvst_refresh ()
607 if (_lxvst_plugin_info) {
608 _lxvst_plugin_info->clear ();
610 _lxvst_plugin_info = new ARDOUR::PluginInfoList();
613 if (lxvst_path.length() == 0) {
614 lxvst_path = "/usr/local/lib64/lxvst:/usr/local/lib/lxvst:/usr/lib64/lxvst:/usr/lib/lxvst";
617 lxvst_discover_from_path (lxvst_path);
621 PluginManager::add_lxvst_directory (string path)
623 if (lxvst_discover_from_path (path) == 0) {
631 static bool lxvst_filter (const string& str, void *)
633 /* Not a dotfile, has a prefix before a period, suffix is "so" */
635 return str[0] != '.' && (str.length() > 3 && str.find (".so") == (str.length() - 3));
639 PluginManager::lxvst_discover_from_path (string path)
642 vector<string *> *plugin_objects;
643 vector<string *>::iterator x;
650 DEBUG_TRACE (DEBUG::PluginManager, string_compose ("Discovering linuxVST plugins along %1\n", path));
652 plugin_objects = scanner (lxvst_path, lxvst_filter, 0, false, true);
654 if (plugin_objects) {
655 for (x = plugin_objects->begin(); x != plugin_objects->end (); ++x) {
656 lxvst_discover (**x);
659 vector_delete (plugin_objects);
666 PluginManager::lxvst_discover (string path)
671 DEBUG_TRACE (DEBUG::PluginManager, string_compose ("checking apparent LXVST plugin at %1\n", path));
673 if ((finfo = vstfx_get_info (const_cast<char *> (path.c_str()))) == 0) {
677 if (!finfo->canProcessReplacing) {
678 warning << string_compose (_("linuxVST plugin %1 does not support processReplacing, and so cannot be used in %2 at this time"),
679 finfo->name, PROGRAM_NAME)
683 PluginInfoPtr info(new LXVSTPluginInfo);
685 if (!strcasecmp ("The Unnamed plugin", finfo->name)) {
686 info->name = PBD::basename_nosuffix (path);
688 info->name = finfo->name;
692 snprintf (buf, sizeof (buf), "%d", finfo->UniqueID);
693 info->unique_id = buf;
694 info->category = "linuxVSTs";
696 info->creator = finfo->creator;
698 info->n_inputs.set_audio (finfo->numInputs);
699 info->n_outputs.set_audio (finfo->numOutputs);
700 info->n_inputs.set_midi (finfo->wantMidi ? 1 : 0);
701 info->type = ARDOUR::LXVST;
703 /* Make sure we don't find the same plugin in more than one place along
704 the LXVST_PATH We can't use a simple 'find' because the path is included
705 in the PluginInfo, and that is the one thing we can be sure MUST be
706 different if a duplicate instance is found. So we just compare the type
707 and unique ID (which for some VSTs isn't actually unique...)
710 if (!_lxvst_plugin_info->empty()) {
711 for (PluginInfoList::iterator i =_lxvst_plugin_info->begin(); i != _lxvst_plugin_info->end(); ++i) {
712 if ((info->type == (*i)->type)&&(info->unique_id == (*i)->unique_id)) {
713 warning << "Ignoring duplicate Linux VST plugin " << info->name << "\n";
714 vstfx_free_info(finfo);
720 _lxvst_plugin_info->push_back (info);
721 vstfx_free_info (finfo);
726 #endif // LXVST_SUPPORT
729 PluginManager::PluginStatusType
730 PluginManager::get_status (const PluginInfoPtr& pi)
732 PluginStatus ps (pi->type, pi->unique_id);
733 PluginStatusList::const_iterator i = find (statuses.begin(), statuses.end(), ps);
734 if (i == statuses.end() ) {
742 PluginManager::save_statuses ()
745 std::string path = Glib::build_filename (user_config_directory(), "plugin_statuses");
747 ofs.open (path.c_str(), ios_base::openmode (ios::out|ios::trunc));
753 for (PluginStatusList::iterator i = statuses.begin(); i != statuses.end(); ++i) {
765 ofs << "Windows-VST";
774 switch ((*i).status) {
787 ofs << (*i).unique_id;;
795 PluginManager::load_statuses ()
797 std::string path = Glib::build_filename (user_config_directory(), "plugin_statuses");
798 ifstream ifs (path.c_str());
808 PluginStatusType status;
825 /* rest of the line is the plugin ID */
827 ifs.getline (buf, sizeof (buf), '\n');
832 if (sstatus == "Normal") {
834 } else if (sstatus == "Favorite") {
836 } else if (sstatus == "Hidden") {
839 error << string_compose (_("unknown plugin status type \"%1\" - all entries ignored"), sstatus)
845 if (stype == "LADSPA") {
847 } else if (stype == "AudioUnit") {
849 } else if (stype == "LV2") {
851 } else if (stype == "Windows-VST") {
853 } else if (stype == "LXVST") {
856 error << string_compose (_("unknown plugin type \"%1\" - ignored"), stype)
862 strip_whitespace_edges (id);
863 set_status (type, id, status);
870 PluginManager::set_status (PluginType t, string id, PluginStatusType status)
872 PluginStatus ps (t, id, status);
875 if (status == Normal) {
879 statuses.insert (ps);
882 ARDOUR::PluginInfoList&
883 PluginManager::windows_vst_plugin_info ()
885 #ifdef WINDOWS_VST_SUPPORT
886 if (!_windows_vst_plugin_info) {
887 windows_vst_refresh ();
889 return *_windows_vst_plugin_info;
891 return _empty_plugin_info;
895 ARDOUR::PluginInfoList&
896 PluginManager::lxvst_plugin_info ()
899 if (!_lxvst_plugin_info)
901 return *_lxvst_plugin_info;
903 return _empty_plugin_info;
907 ARDOUR::PluginInfoList&
908 PluginManager::ladspa_plugin_info ()
910 if (!_ladspa_plugin_info)
912 return *_ladspa_plugin_info;
915 ARDOUR::PluginInfoList&
916 PluginManager::lv2_plugin_info ()
919 if (!_lv2_plugin_info)
921 return *_lv2_plugin_info;
923 return _empty_plugin_info;
927 ARDOUR::PluginInfoList&
928 PluginManager::au_plugin_info ()
930 #ifdef AUDIOUNIT_SUPPORT
931 if (!_au_plugin_info)
933 return *_au_plugin_info;
935 return _empty_plugin_info;