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;
646 DEBUG_TRACE (DEBUG::PluginManager, string_compose ("Discovering linuxVST plugins along %1\n", path));
648 plugin_objects = scanner (lxvst_path, lxvst_filter, 0, false, true);
650 if (plugin_objects) {
651 for (x = plugin_objects->begin(); x != plugin_objects->end (); ++x) {
652 lxvst_discover (**x);
655 vector_delete (plugin_objects);
662 PluginManager::lxvst_discover (string path)
667 DEBUG_TRACE (DEBUG::PluginManager, string_compose ("checking apparent LXVST plugin at %1\n", path));
669 if ((finfo = vstfx_get_info (const_cast<char *> (path.c_str()))) == 0) {
673 if (!finfo->canProcessReplacing) {
674 warning << string_compose (_("linuxVST plugin %1 does not support processReplacing, and so cannot be used in %2 at this time"),
675 finfo->name, PROGRAM_NAME)
679 PluginInfoPtr info(new LXVSTPluginInfo);
681 if (!strcasecmp ("The Unnamed plugin", finfo->name)) {
682 info->name = PBD::basename_nosuffix (path);
684 info->name = finfo->name;
688 snprintf (buf, sizeof (buf), "%d", finfo->UniqueID);
689 info->unique_id = buf;
690 info->category = "linuxVSTs";
692 info->creator = finfo->creator;
694 info->n_inputs.set_audio (finfo->numInputs);
695 info->n_outputs.set_audio (finfo->numOutputs);
696 info->n_inputs.set_midi (finfo->wantMidi ? 1 : 0);
697 info->type = ARDOUR::LXVST;
699 /* Make sure we don't find the same plugin in more than one place along
700 the LXVST_PATH We can't use a simple 'find' because the path is included
701 in the PluginInfo, and that is the one thing we can be sure MUST be
702 different if a duplicate instance is found. So we just compare the type
703 and unique ID (which for some VSTs isn't actually unique...)
706 if (!_lxvst_plugin_info->empty()) {
707 for (PluginInfoList::iterator i =_lxvst_plugin_info->begin(); i != _lxvst_plugin_info->end(); ++i) {
708 if ((info->type == (*i)->type)&&(info->unique_id == (*i)->unique_id)) {
709 warning << "Ignoring duplicate Linux VST plugin " << info->name << "\n";
710 vstfx_free_info(finfo);
716 _lxvst_plugin_info->push_back (info);
717 vstfx_free_info (finfo);
722 #endif // LXVST_SUPPORT
725 PluginManager::PluginStatusType
726 PluginManager::get_status (const PluginInfoPtr& pi)
728 PluginStatus ps (pi->type, pi->unique_id);
729 PluginStatusList::const_iterator i = find (statuses.begin(), statuses.end(), ps);
730 if (i == statuses.end() ) {
738 PluginManager::save_statuses ()
741 std::string path = Glib::build_filename (user_config_directory(), "plugin_statuses");
743 ofs.open (path.c_str(), ios_base::openmode (ios::out|ios::trunc));
749 for (PluginStatusList::iterator i = statuses.begin(); i != statuses.end(); ++i) {
761 ofs << "Windows-VST";
770 switch ((*i).status) {
783 ofs << (*i).unique_id;;
791 PluginManager::load_statuses ()
793 std::string path = Glib::build_filename (user_config_directory(), "plugin_statuses");
794 ifstream ifs (path.c_str());
804 PluginStatusType status;
821 /* rest of the line is the plugin ID */
823 ifs.getline (buf, sizeof (buf), '\n');
828 if (sstatus == "Normal") {
830 } else if (sstatus == "Favorite") {
832 } else if (sstatus == "Hidden") {
835 error << string_compose (_("unknown plugin status type \"%1\" - all entries ignored"), sstatus)
841 if (stype == "LADSPA") {
843 } else if (stype == "AudioUnit") {
845 } else if (stype == "LV2") {
847 } else if (stype == "Windows-VST") {
849 } else if (stype == "LXVST") {
852 error << string_compose (_("unknown plugin type \"%1\" - ignored"), stype)
858 strip_whitespace_edges (id);
859 set_status (type, id, status);
866 PluginManager::set_status (PluginType t, string id, PluginStatusType status)
868 PluginStatus ps (t, id, status);
871 if (status == Normal) {
875 statuses.insert (ps);
878 ARDOUR::PluginInfoList&
879 PluginManager::windows_vst_plugin_info ()
881 #ifdef WINDOWS_VST_SUPPORT
882 if (!_windows_vst_plugin_info) {
883 windows_vst_refresh ();
885 return *_windows_vst_plugin_info;
887 return _empty_plugin_info;
891 ARDOUR::PluginInfoList&
892 PluginManager::lxvst_plugin_info ()
895 if (!_lxvst_plugin_info)
897 return *_lxvst_plugin_info;
899 return _empty_plugin_info;
903 ARDOUR::PluginInfoList&
904 PluginManager::ladspa_plugin_info ()
906 if (!_ladspa_plugin_info)
908 return *_ladspa_plugin_info;
911 ARDOUR::PluginInfoList&
912 PluginManager::lv2_plugin_info ()
915 if (!_lv2_plugin_info)
917 return *_lv2_plugin_info;
919 return _empty_plugin_info;
923 ARDOUR::PluginInfoList&
924 PluginManager::au_plugin_info ()
926 #ifdef AUDIOUNIT_SUPPORT
927 if (!_au_plugin_info)
929 return *_au_plugin_info;
931 return _empty_plugin_info;