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>
33 #ifdef WINDOWS_VST_SUPPORT
35 #include "pbd/basename.h"
37 #endif // WINDOWS_VST_SUPPORT
40 #include "ardour/linux_vst_support.h"
41 #include "pbd/basename.h"
43 #endif //LXVST_SUPPORT
45 #include <glibmm/miscutils.h>
47 #include "pbd/pathscanner.h"
48 #include "pbd/whitespace.h"
49 #include "pbd/filesystem.h"
51 #include "ardour/debug.h"
52 #include "ardour/filesystem_paths.h"
53 #include "ardour/ladspa.h"
54 #include "ardour/ladspa_plugin.h"
55 #include "ardour/plugin.h"
56 #include "ardour/plugin_manager.h"
57 #include "ardour/rc_configuration.h"
60 #include "ardour/lv2_plugin.h"
63 #ifdef WINDOWS_VST_SUPPORT
64 #include "ardour/windows_vst_plugin.h"
68 #include "ardour/lxvst_plugin.h"
71 #ifdef AUDIOUNIT_SUPPORT
72 #include "ardour/audio_unit.h"
73 #include <Carbon/Carbon.h>
76 #include "pbd/error.h"
77 #include "pbd/stl_delete.h"
81 using namespace ARDOUR;
85 PluginManager* PluginManager::_instance = 0;
88 PluginManager::instance()
91 _instance = new PluginManager;
96 PluginManager::PluginManager ()
97 : _windows_vst_plugin_info(0)
98 , _lxvst_plugin_info(0)
99 , _ladspa_plugin_info(0)
100 , _lv2_plugin_info(0)
108 if ((s = getenv ("LADSPA_RDF_PATH"))){
112 if (lrdf_path.length() == 0) {
113 lrdf_path = "/usr/local/share/ladspa/rdf:/usr/share/ladspa/rdf";
116 add_lrdf_data(lrdf_path);
117 add_ladspa_presets();
118 #ifdef WINDOWS_VST_SUPPORT
119 if (Config->get_use_windows_vst ()) {
120 add_windows_vst_presets ();
122 #endif /* WINDOWS_VST_SUPPORT */
125 if (Config->get_use_lxvst()) {
128 #endif /* Native LinuxVST support*/
130 if ((s = getenv ("LADSPA_PATH"))) {
134 if ((s = getenv ("VST_PATH"))) {
135 windows_vst_path = s;
136 } else if ((s = getenv ("VST_PLUGINS"))) {
137 windows_vst_path = s;
140 if ((s = getenv ("LXVST_PATH"))) {
142 } else if ((s = getenv ("LXVST_PLUGINS"))) {
146 if (_instance == 0) {
150 /* the plugin manager is constructed too early to use Profile */
152 if (getenv ("ARDOUR_SAE")) {
153 ladspa_plugin_whitelist.push_back (1203); // single band parametric
154 ladspa_plugin_whitelist.push_back (1772); // caps compressor
155 ladspa_plugin_whitelist.push_back (1913); // fast lookahead limiter
156 ladspa_plugin_whitelist.push_back (1075); // simple RMS expander
157 ladspa_plugin_whitelist.push_back (1061); // feedback delay line (max 5s)
158 ladspa_plugin_whitelist.push_back (1216); // gverb
159 ladspa_plugin_whitelist.push_back (2150); // tap pitch shifter
162 BootMessage (_("Discovering Plugins"));
166 PluginManager::~PluginManager()
172 PluginManager::refresh ()
174 DEBUG_TRACE (DEBUG::PluginManager, "PluginManager::refresh\n");
180 #ifdef WINDOWS_VST_SUPPORT
181 if (Config->get_use_windows_vst()) {
182 windows_vst_refresh ();
184 #endif // WINDOWS_VST_SUPPORT
187 if(Config->get_use_lxvst()) {
190 #endif //Native linuxVST SUPPORT
192 #ifdef AUDIOUNIT_SUPPORT
196 PluginListChanged (); /* EMIT SIGNAL */
200 PluginManager::ladspa_refresh ()
202 if (_ladspa_plugin_info)
203 _ladspa_plugin_info->clear ();
205 _ladspa_plugin_info = new ARDOUR::PluginInfoList ();
207 static const char *standard_paths[] = {
208 "/usr/local/lib64/ladspa",
209 "/usr/local/lib/ladspa",
212 "/Library/Audio/Plug-Ins/LADSPA",
216 /* allow LADSPA_PATH to augment, not override standard locations */
218 /* Only add standard locations to ladspa_path if it doesn't
219 * already contain them. Check for trailing G_DIR_SEPARATOR too.
223 for (i = 0; standard_paths[i][0]; i++) {
224 size_t found = ladspa_path.find(standard_paths[i]);
225 if (found != ladspa_path.npos) {
226 switch (ladspa_path[found + strlen(standard_paths[i])]) {
230 case G_DIR_SEPARATOR :
231 if (ladspa_path[found + strlen(standard_paths[i]) + 1] == ':' ||
232 ladspa_path[found + strlen(standard_paths[i]) + 1] == '\0') {
237 if (!ladspa_path.empty())
240 ladspa_path += standard_paths[i];
244 DEBUG_TRACE (DEBUG::PluginManager, string_compose ("LADSPA: search along: [%1]\n", ladspa_path));
246 ladspa_discover_from_path (ladspa_path);
251 PluginManager::add_ladspa_directory (string path)
253 if (ladspa_discover_from_path (path) == 0) {
261 static bool ladspa_filter (const string& str, void */*arg*/)
263 /* Not a dotfile, has a prefix before a period, suffix is "so" */
265 return str[0] != '.' && (str.length() > 3 && str.find (".so") == (str.length() - 3));
269 PluginManager::ladspa_discover_from_path (string /*path*/)
272 vector<string *> *plugin_objects;
273 vector<string *>::iterator x;
276 plugin_objects = scanner (ladspa_path, ladspa_filter, 0, false, true);
278 if (plugin_objects) {
279 for (x = plugin_objects->begin(); x != plugin_objects->end (); ++x) {
280 ladspa_discover (**x);
284 vector_delete (plugin_objects);
288 static bool rdf_filter (const string &str, void* /*arg*/)
290 return str[0] != '.' &&
291 ((str.find(".rdf") == (str.length() - 4)) ||
292 (str.find(".rdfs") == (str.length() - 5)) ||
293 (str.find(".n3") == (str.length() - 3)) ||
294 (str.find(".ttl") == (str.length() - 4)));
298 PluginManager::add_ladspa_presets()
300 add_presets ("ladspa");
304 PluginManager::add_windows_vst_presets()
306 add_presets ("windows-vst");
310 PluginManager::add_lxvst_presets()
312 add_presets ("lxvst");
316 PluginManager::add_presets(string domain)
320 vector<string *> *presets;
321 vector<string *>::iterator x;
324 if ((envvar = getenv ("HOME")) == 0) {
328 string path = string_compose("%1/.%2/rdf", envvar, domain);
329 presets = scanner (path, rdf_filter, 0, false, true);
332 for (x = presets->begin(); x != presets->end (); ++x) {
333 string file = "file:" + **x;
334 if (lrdf_read_file(file.c_str())) {
335 warning << string_compose(_("Could not parse rdf file: %1"), *x) << endmsg;
340 vector_delete (presets);
344 PluginManager::add_lrdf_data (const string &path)
347 vector<string *>* rdf_files;
348 vector<string *>::iterator x;
350 rdf_files = scanner (path, rdf_filter, 0, false, true);
353 for (x = rdf_files->begin(); x != rdf_files->end (); ++x) {
354 const string uri(string("file://") + **x);
356 if (lrdf_read_file(uri.c_str())) {
357 warning << "Could not parse rdf file: " << uri << endmsg;
362 vector_delete (rdf_files);
366 PluginManager::ladspa_discover (string path)
369 const LADSPA_Descriptor *descriptor;
370 LADSPA_Descriptor_Function dfunc;
373 if ((module = dlopen (path.c_str(), RTLD_NOW)) == 0) {
374 error << string_compose(_("LADSPA: cannot load module \"%1\" (%2)"), path, dlerror()) << endmsg;
378 dfunc = (LADSPA_Descriptor_Function) dlsym (module, "ladspa_descriptor");
380 if ((errstr = dlerror()) != 0) {
381 error << string_compose(_("LADSPA: module \"%1\" has no descriptor function."), path) << endmsg;
382 error << errstr << endmsg;
387 for (uint32_t i = 0; ; ++i) {
388 if ((descriptor = dfunc (i)) == 0) {
392 if (!ladspa_plugin_whitelist.empty()) {
393 if (find (ladspa_plugin_whitelist.begin(), ladspa_plugin_whitelist.end(), descriptor->UniqueID) == ladspa_plugin_whitelist.end()) {
398 PluginInfoPtr info(new LadspaPluginInfo);
399 info->name = descriptor->Name;
400 info->category = get_ladspa_category(descriptor->UniqueID);
401 info->creator = descriptor->Maker;
404 info->n_inputs = ChanCount();
405 info->n_outputs = ChanCount();
406 info->type = ARDOUR::LADSPA;
409 snprintf (buf, sizeof (buf), "%lu", descriptor->UniqueID);
410 info->unique_id = buf;
412 for (uint32_t n=0; n < descriptor->PortCount; ++n) {
413 if ( LADSPA_IS_PORT_AUDIO (descriptor->PortDescriptors[n]) ) {
414 if ( LADSPA_IS_PORT_INPUT (descriptor->PortDescriptors[n]) ) {
415 info->n_inputs.set_audio(info->n_inputs.n_audio() + 1);
417 else if ( LADSPA_IS_PORT_OUTPUT (descriptor->PortDescriptors[n]) ) {
418 info->n_outputs.set_audio(info->n_outputs.n_audio() + 1);
423 if(_ladspa_plugin_info->empty()){
424 _ladspa_plugin_info->push_back (info);
427 //Ensure that the plugin is not already in the plugin list.
431 for (PluginInfoList::const_iterator i = _ladspa_plugin_info->begin(); i != _ladspa_plugin_info->end(); ++i) {
432 if(0 == info->unique_id.compare((*i)->unique_id)){
438 _ladspa_plugin_info->push_back (info);
442 // GDB WILL NOT LIKE YOU IF YOU DO THIS
449 PluginManager::get_ladspa_category (uint32_t plugin_id)
452 lrdf_statement pattern;
454 snprintf(buf, sizeof(buf), "%s%" PRIu32, LADSPA_BASE, plugin_id);
455 pattern.subject = buf;
456 pattern.predicate = (char*)RDF_TYPE;
458 pattern.object_type = lrdf_uri;
460 lrdf_statement* matches1 = lrdf_matches (&pattern);
466 pattern.subject = matches1->object;
467 pattern.predicate = (char*)(LADSPA_BASE "hasLabel");
469 pattern.object_type = lrdf_literal;
471 lrdf_statement* matches2 = lrdf_matches (&pattern);
472 lrdf_free_statements(matches1);
478 string label = matches2->object;
479 lrdf_free_statements(matches2);
481 /* Kludge LADSPA class names to be singular and match LV2 class names.
482 This avoids duplicate plugin menus for every class, which is necessary
483 to make the plugin category menu at all usable, but is obviously a
486 In the short term, lrdf could be updated so the labels match and a new
487 release made. To support both specs, we should probably be mapping the
488 URIs to the same category in code and perhaps tweaking that hierarchy
489 dynamically to suit the user. Personally, I (drobilla) think that time
490 is better spent replacing the little-used LRDF.
492 In the longer term, we will abandon LRDF entirely in favour of LV2 and
493 use that class hierarchy. Aside from fixing this problem properly, that
494 will also allow for translated labels. SWH plugins have been LV2 for
495 ages; TAP needs porting. I don't know of anything else with LRDF data.
497 if (label == "Utilities") {
499 } else if (label == "Pitch shifters") {
500 return "Pitch Shifter";
501 } else if (label != "Dynamics" && label != "Chorus"
502 &&label[label.length() - 1] == 's'
503 && label[label.length() - 2] != 's') {
504 return label.substr(0, label.length() - 1);
512 PluginManager::lv2_refresh ()
514 delete _lv2_plugin_info;
515 _lv2_plugin_info = LV2PluginInfo::discover();
519 #ifdef AUDIOUNIT_SUPPORT
521 PluginManager::au_refresh ()
523 DEBUG_TRACE (DEBUG::PluginManager, "AU: refresh\n");
524 delete _au_plugin_info;
525 _au_plugin_info = AUPluginInfo::discover();
530 #ifdef WINDOWS_VST_SUPPORT
533 PluginManager::windows_vst_refresh ()
535 if (_windows_vst_plugin_info) {
536 _windows_vst_plugin_info->clear ();
538 _windows_vst_plugin_info = new ARDOUR::PluginInfoList();
541 if (windows_vst_path.length() == 0) {
542 windows_vst_path = "/usr/local/lib/vst:/usr/lib/vst";
545 windows_vst_discover_from_path (windows_vst_path);
549 PluginManager::add_windows_vst_directory (string path)
551 if (windows_vst_discover_from_path (path) == 0) {
552 windows_vst_path += ':';
553 windows_vst_path += path;
559 static bool windows_vst_filter (const string& str, void *arg)
561 /* Not a dotfile, has a prefix before a period, suffix is "dll" */
563 return str[0] != '.' && (str.length() > 4 && str.find (".dll") == (str.length() - 4));
567 PluginManager::windows_vst_discover_from_path (string path)
570 vector<string *> *plugin_objects;
571 vector<string *>::iterator x;
574 DEBUG_TRACE (DEBUG::PluginManager, string_compose ("detecting Windows VST plugins along %1\n", path));
576 plugin_objects = scanner (windows_vst_path, windows_vst_filter, 0, false, true);
578 if (plugin_objects) {
579 for (x = plugin_objects->begin(); x != plugin_objects->end (); ++x) {
580 windows_vst_discover (**x);
584 vector_delete (plugin_objects);
589 PluginManager::windows_vst_discover (string path)
594 if ((finfo = fst_get_info (const_cast<char *> (path.c_str()))) == 0) {
595 warning << "Cannot get Windows VST information from " << path << endmsg;
599 if (!finfo->canProcessReplacing) {
600 warning << string_compose (_("VST plugin %1 does not support processReplacing, and so cannot be used in ardour at this time"),
605 PluginInfoPtr info (new WindowsVSTPluginInfo);
607 /* what a joke freeware VST is */
609 if (!strcasecmp ("The Unnamed plugin", finfo->name)) {
610 info->name = PBD::basename_nosuffix (path);
612 info->name = finfo->name;
616 snprintf (buf, sizeof (buf), "%d", finfo->UniqueID);
617 info->unique_id = buf;
618 info->category = "VST";
620 info->creator = finfo->creator;
622 info->n_inputs.set_audio (finfo->numInputs);
623 info->n_outputs.set_audio (finfo->numOutputs);
624 info->n_inputs.set_midi (finfo->wantMidi ? 1 : 0);
625 info->type = ARDOUR::Windows_VST;
627 _windows_vst_plugin_info->push_back (info);
628 fst_free_info (finfo);
633 #endif // WINDOWS_VST_SUPPORT
638 PluginManager::lxvst_refresh ()
640 if (_lxvst_plugin_info) {
641 _lxvst_plugin_info->clear ();
643 _lxvst_plugin_info = new ARDOUR::PluginInfoList();
646 if (lxvst_path.length() == 0) {
647 lxvst_path = "/usr/local/lib64/lxvst:/usr/local/lib/lxvst:/usr/lib64/lxvst:/usr/lib/lxvst";
650 lxvst_discover_from_path (lxvst_path);
654 PluginManager::add_lxvst_directory (string path)
656 if (lxvst_discover_from_path (path) == 0) {
664 static bool lxvst_filter (const string& str, void *)
666 /* Not a dotfile, has a prefix before a period, suffix is "so" */
668 return str[0] != '.' && (str.length() > 3 && str.find (".so") == (str.length() - 3));
672 PluginManager::lxvst_discover_from_path (string path)
675 vector<string *> *plugin_objects;
676 vector<string *>::iterator x;
679 DEBUG_TRACE (DEBUG::PluginManager, string_compose ("Discovering linuxVST plugins along %1\n", path));
681 plugin_objects = scanner (lxvst_path, lxvst_filter, 0, false, true);
683 if (plugin_objects) {
684 for (x = plugin_objects->begin(); x != plugin_objects->end (); ++x) {
685 lxvst_discover (**x);
689 vector_delete (plugin_objects);
694 PluginManager::lxvst_discover (string path)
699 if ((finfo = vstfx_get_info (const_cast<char *> (path.c_str()))) == 0) {
703 if (!finfo->canProcessReplacing) {
704 warning << string_compose (_("linuxVST plugin %1 does not support processReplacing, and so cannot be used in ardour at this time"),
709 PluginInfoPtr info(new LXVSTPluginInfo);
711 if (!strcasecmp ("The Unnamed plugin", finfo->name)) {
712 info->name = PBD::basename_nosuffix (path);
714 info->name = finfo->name;
718 snprintf (buf, sizeof (buf), "%d", finfo->UniqueID);
719 info->unique_id = buf;
720 info->category = "linuxVSTs";
722 info->creator = finfo->creator;
724 info->n_inputs.set_audio (finfo->numInputs);
725 info->n_outputs.set_audio (finfo->numOutputs);
726 info->n_inputs.set_midi (finfo->wantMidi ? 1 : 0);
727 info->type = ARDOUR::LXVST;
729 /* Make sure we don't find the same plugin in more than one place along
730 the LXVST_PATH We can't use a simple 'find' because the path is included
731 in the PluginInfo, and that is the one thing we can be sure MUST be
732 different if a duplicate instance is found. So we just compare the type
733 and unique ID (which for some VSTs isn't actually unique...)
736 if (!_lxvst_plugin_info->empty()) {
737 for (PluginInfoList::iterator i =_lxvst_plugin_info->begin(); i != _lxvst_plugin_info->end(); ++i) {
738 if ((info->type == (*i)->type)&&(info->unique_id == (*i)->unique_id)) {
739 warning << "Ignoring duplicate Linux VST plugin " << info->name << "\n";
740 vstfx_free_info(finfo);
746 _lxvst_plugin_info->push_back (info);
747 vstfx_free_info (finfo);
752 #endif // LXVST_SUPPORT
755 PluginManager::PluginStatusType
756 PluginManager::get_status (const PluginInfoPtr& pi)
758 PluginStatus ps (pi->type, pi->unique_id);
759 PluginStatusList::const_iterator i = find (statuses.begin(), statuses.end(), ps);
760 if (i == statuses.end() ) {
768 PluginManager::save_statuses ()
771 sys::path path = user_config_directory();
772 path /= "plugin_statuses";
774 ofs.open (path.to_string().c_str(), ios_base::openmode (ios::out|ios::trunc));
780 for (PluginStatusList::iterator i = statuses.begin(); i != statuses.end(); ++i) {
792 ofs << "Windows-VST";
801 switch ((*i).status) {
814 ofs << (*i).unique_id;;
822 PluginManager::load_statuses ()
824 sys::path path = user_config_directory();
825 path /= "plugin_statuses";
826 ifstream ifs (path.to_string().c_str());
836 PluginStatusType status;
853 /* rest of the line is the plugin ID */
855 ifs.getline (buf, sizeof (buf), '\n');
860 if (sstatus == "Normal") {
862 } else if (sstatus == "Favorite") {
864 } else if (sstatus == "Hidden") {
867 error << string_compose (_("unknown plugin status type \"%1\" - all entries ignored"), sstatus)
873 if (stype == "LADSPA") {
875 } else if (stype == "AudioUnit") {
877 } else if (stype == "LV2") {
879 } else if (stype == "Windows-VST") {
881 } else if (stype == "LXVST") {
884 error << string_compose (_("unknown plugin type \"%1\" - ignored"), stype)
890 strip_whitespace_edges (id);
891 set_status (type, id, status);
898 PluginManager::set_status (PluginType t, string id, PluginStatusType status)
900 PluginStatus ps (t, id, status);
903 if (status == Normal) {
907 statuses.insert (ps);
910 ARDOUR::PluginInfoList&
911 PluginManager::windows_vst_plugin_info ()
913 #ifdef WINDOWS_VST_SUPPORT
914 if (!_windows_vst_plugin_info) {
915 windows_vst_refresh ();
917 return *_windows_vst_plugin_info;
919 return _empty_plugin_info;
923 ARDOUR::PluginInfoList&
924 PluginManager::lxvst_plugin_info ()
927 if (!_lxvst_plugin_info)
929 return *_lxvst_plugin_info;
931 return _empty_plugin_info;
935 ARDOUR::PluginInfoList&
936 PluginManager::ladspa_plugin_info ()
938 if (!_ladspa_plugin_info)
940 return *_ladspa_plugin_info;
943 ARDOUR::PluginInfoList&
944 PluginManager::lv2_plugin_info ()
947 if (!_lv2_plugin_info)
949 return *_lv2_plugin_info;
951 return _empty_plugin_info;
955 ARDOUR::PluginInfoList&
956 PluginManager::au_plugin_info ()
958 #ifdef AUDIOUNIT_SUPPORT
959 if (!_au_plugin_info)
961 return *_au_plugin_info;
963 return _empty_plugin_info;