various fixes to MidiRegionView selection handling, key handling, drawing of ghost...
[ardour2.git] / libs / ardour / plugin_manager.cc
blob912fc20dcda350fb6f6c1ac510f58860a8eb92b2
1 /*
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.
20 #ifdef WAF_BUILD
21 #include "libardour-config.h"
22 #endif
24 #include <stdint.h>
26 #include <sys/types.h>
27 #include <cstdio>
28 #include <lrdf.h>
29 #include <dlfcn.h>
30 #include <cstdlib>
31 #include <fstream>
33 #ifdef VST_SUPPORT
34 #include <fst.h>
35 #include "pbd/basename.h"
36 #include <cstring>
37 #endif // VST_SUPPORT
39 #include <glibmm/miscutils.h>
41 #include "pbd/pathscanner.h"
42 #include "pbd/whitespace.h"
44 #include "ardour/ladspa.h"
45 #include "ardour/session.h"
46 #include "ardour/plugin_manager.h"
47 #include "ardour/plugin.h"
48 #include "ardour/ladspa_plugin.h"
49 #include "ardour/filesystem_paths.h"
51 #ifdef LV2_SUPPORT
52 #include "ardour/lv2_plugin.h"
53 #endif
55 #ifdef VST_SUPPORT
56 #include "ardour/vst_plugin.h"
57 #endif
59 #ifdef HAVE_AUDIOUNITS
60 #include "ardour/audio_unit.h"
61 #include <Carbon/Carbon.h>
62 #endif
64 #include "pbd/error.h"
65 #include "pbd/stl_delete.h"
67 #include "i18n.h"
69 using namespace ARDOUR;
70 using namespace PBD;
71 using namespace std;
73 PluginManager* PluginManager::_manager = 0;
75 PluginManager::PluginManager ()
76 : _vst_plugin_info(0)
77 , _ladspa_plugin_info(0)
78 , _lv2_plugin_info(0)
79 , _au_plugin_info(0)
81 char* s;
82 string lrdf_path;
84 load_statuses ();
86 #ifdef HAVE_AUDIOUNITS
87 ProcessSerialNumber psn = { 0, kCurrentProcess };
88 OSStatus returnCode = TransformProcessType(& psn, kProcessTransformToForegroundApplication);
89 if( returnCode != 0) {
90 error << _("Cannot become GUI app") << endmsg;
92 #endif
94 if ((s = getenv ("LADSPA_RDF_PATH"))){
95 lrdf_path = s;
98 if (lrdf_path.length() == 0) {
99 lrdf_path = "/usr/local/share/ladspa/rdf:/usr/share/ladspa/rdf";
102 add_lrdf_data(lrdf_path);
103 add_ladspa_presets();
104 #ifdef VST_SUPPORT
105 if (Config->get_use_vst()) {
106 add_vst_presets();
108 #endif /* VST_SUPPORT */
110 if ((s = getenv ("LADSPA_PATH"))) {
111 ladspa_path = s;
114 if ((s = getenv ("VST_PATH"))) {
115 vst_path = s;
116 } else if ((s = getenv ("VST_PLUGINS"))) {
117 vst_path = s;
120 if (_manager == 0) {
121 _manager = this;
124 /* the plugin manager is constructed too early to use Profile */
126 if (getenv ("ARDOUR_SAE")) {
127 ladspa_plugin_whitelist.push_back (1203); // single band parametric
128 ladspa_plugin_whitelist.push_back (1772); // caps compressor
129 ladspa_plugin_whitelist.push_back (1913); // fast lookahead limiter
130 ladspa_plugin_whitelist.push_back (1075); // simple RMS expander
131 ladspa_plugin_whitelist.push_back (1061); // feedback delay line (max 5s)
132 ladspa_plugin_whitelist.push_back (1216); // gverb
133 ladspa_plugin_whitelist.push_back (2150); // tap pitch shifter
136 BootMessage (_("Discovering Plugins"));
140 PluginManager::~PluginManager()
145 void
146 PluginManager::refresh ()
148 ladspa_refresh ();
149 #ifdef LV2_SUPPORT
150 lv2_refresh ();
151 #endif
152 #ifdef VST_SUPPORT
153 if (Config->get_use_vst()) {
154 vst_refresh ();
156 #endif // VST_SUPPORT
157 #ifdef HAVE_AUDIOUNITS
158 au_refresh ();
159 #endif
161 PluginListChanged (); /* EMIT SIGNAL */
164 void
165 PluginManager::ladspa_refresh ()
167 if (_ladspa_plugin_info)
168 _ladspa_plugin_info->clear ();
169 else
170 _ladspa_plugin_info = new ARDOUR::PluginInfoList ();
172 static const char *standard_paths[] = {
173 "/usr/local/lib64/ladspa",
174 "/usr/local/lib/ladspa",
175 "/usr/lib64/ladspa",
176 "/usr/lib/ladspa",
177 "/Library/Audio/Plug-Ins/LADSPA",
181 /* allow LADSPA_PATH to augment, not override standard locations */
183 /* Only add standard locations to ladspa_path if it doesn't
184 * already contain them. Check for trailing G_DIR_SEPARATOR too.
187 int i;
188 for (i = 0; standard_paths[i][0]; i++) {
189 size_t found = ladspa_path.find(standard_paths[i]);
190 if (found != ladspa_path.npos) {
191 switch (ladspa_path[found + strlen(standard_paths[i])]) {
192 case ':' :
193 case '\0':
194 continue;
195 case G_DIR_SEPARATOR :
196 if (ladspa_path[found + strlen(standard_paths[i]) + 1] == ':' ||
197 ladspa_path[found + strlen(standard_paths[i]) + 1] == '\0') {
198 continue;
202 if (!ladspa_path.empty())
203 ladspa_path += ":";
205 ladspa_path += standard_paths[i];
209 ladspa_discover_from_path (ladspa_path);
214 PluginManager::add_ladspa_directory (string path)
216 if (ladspa_discover_from_path (path) == 0) {
217 ladspa_path += ':';
218 ladspa_path += path;
219 return 0;
221 return -1;
224 static bool ladspa_filter (const string& str, void */*arg*/)
226 /* Not a dotfile, has a prefix before a period, suffix is "so" */
228 return str[0] != '.' && (str.length() > 3 && str.find (".so") == (str.length() - 3));
232 PluginManager::ladspa_discover_from_path (string /*path*/)
234 PathScanner scanner;
235 vector<string *> *plugin_objects;
236 vector<string *>::iterator x;
237 int ret = 0;
239 plugin_objects = scanner (ladspa_path, ladspa_filter, 0, true, true);
241 if (plugin_objects) {
242 for (x = plugin_objects->begin(); x != plugin_objects->end (); ++x) {
243 ladspa_discover (**x);
247 vector_delete (plugin_objects);
248 return ret;
251 static bool rdf_filter (const string &str, void* /*arg*/)
253 return str[0] != '.' &&
254 ((str.find(".rdf") == (str.length() - 4)) ||
255 (str.find(".rdfs") == (str.length() - 5)) ||
256 (str.find(".n3") == (str.length() - 3)) ||
257 (str.find(".ttl") == (str.length() - 4)));
260 void
261 PluginManager::add_ladspa_presets()
263 add_presets ("ladspa");
266 void
267 PluginManager::add_vst_presets()
269 add_presets ("vst");
271 void
272 PluginManager::add_presets(string domain)
275 PathScanner scanner;
276 vector<string *> *presets;
277 vector<string *>::iterator x;
279 char* envvar;
280 if ((envvar = getenv ("HOME")) == 0) {
281 return;
284 string path = string_compose("%1/.%2/rdf", envvar, domain);
285 presets = scanner (path, rdf_filter, 0, true, true);
287 if (presets) {
288 for (x = presets->begin(); x != presets->end (); ++x) {
289 string file = "file:" + **x;
290 if (lrdf_read_file(file.c_str())) {
291 warning << string_compose(_("Could not parse rdf file: %1"), *x) << endmsg;
296 vector_delete (presets);
299 void
300 PluginManager::add_lrdf_data (const string &path)
302 PathScanner scanner;
303 vector<string *>* rdf_files;
304 vector<string *>::iterator x;
306 rdf_files = scanner (path, rdf_filter, 0, true, true);
308 if (rdf_files) {
309 for (x = rdf_files->begin(); x != rdf_files->end (); ++x) {
310 const string uri(string("file://") + **x);
312 if (lrdf_read_file(uri.c_str())) {
313 warning << "Could not parse rdf file: " << uri << endmsg;
318 vector_delete (rdf_files);
322 PluginManager::ladspa_discover (string path)
324 void *module;
325 const LADSPA_Descriptor *descriptor;
326 LADSPA_Descriptor_Function dfunc;
327 const char *errstr;
329 if ((module = dlopen (path.c_str(), RTLD_NOW)) == 0) {
330 error << string_compose(_("LADSPA: cannot load module \"%1\" (%2)"), path, dlerror()) << endmsg;
331 return -1;
334 dfunc = (LADSPA_Descriptor_Function) dlsym (module, "ladspa_descriptor");
336 if ((errstr = dlerror()) != 0) {
337 error << string_compose(_("LADSPA: module \"%1\" has no descriptor function."), path) << endmsg;
338 error << errstr << endmsg;
339 dlclose (module);
340 return -1;
343 for (uint32_t i = 0; ; ++i) {
344 if ((descriptor = dfunc (i)) == 0) {
345 break;
348 if (!ladspa_plugin_whitelist.empty()) {
349 if (find (ladspa_plugin_whitelist.begin(), ladspa_plugin_whitelist.end(), descriptor->UniqueID) == ladspa_plugin_whitelist.end()) {
350 continue;
354 PluginInfoPtr info(new LadspaPluginInfo);
355 info->name = descriptor->Name;
356 info->category = get_ladspa_category(descriptor->UniqueID);
357 info->creator = descriptor->Maker;
358 info->path = path;
359 info->index = i;
360 info->n_inputs = ChanCount();
361 info->n_outputs = ChanCount();
362 info->type = ARDOUR::LADSPA;
364 char buf[32];
365 snprintf (buf, sizeof (buf), "%lu", descriptor->UniqueID);
366 info->unique_id = buf;
368 for (uint32_t n=0; n < descriptor->PortCount; ++n) {
369 if ( LADSPA_IS_PORT_AUDIO (descriptor->PortDescriptors[n]) ) {
370 if ( LADSPA_IS_PORT_INPUT (descriptor->PortDescriptors[n]) ) {
371 info->n_inputs.set_audio(info->n_inputs.n_audio() + 1);
373 else if ( LADSPA_IS_PORT_OUTPUT (descriptor->PortDescriptors[n]) ) {
374 info->n_outputs.set_audio(info->n_outputs.n_audio() + 1);
379 if(_ladspa_plugin_info->empty()){
380 _ladspa_plugin_info->push_back (info);
383 //Ensure that the plugin is not already in the plugin list.
385 bool found = false;
387 for (PluginInfoList::const_iterator i = _ladspa_plugin_info->begin(); i != _ladspa_plugin_info->end(); ++i) {
388 if(0 == info->unique_id.compare((*i)->unique_id)){
389 found = true;
393 if(!found){
394 _ladspa_plugin_info->push_back (info);
398 // GDB WILL NOT LIKE YOU IF YOU DO THIS
399 // dlclose (module);
401 return 0;
404 string
405 PluginManager::get_ladspa_category (uint32_t plugin_id)
407 char buf[256];
408 lrdf_statement pattern;
410 snprintf(buf, sizeof(buf), "%s%" PRIu32, LADSPA_BASE, plugin_id);
411 pattern.subject = buf;
412 pattern.predicate = (char*)RDF_TYPE;
413 pattern.object = 0;
414 pattern.object_type = lrdf_uri;
416 lrdf_statement* matches1 = lrdf_matches (&pattern);
418 if (!matches1) {
419 return "Unknown";
422 pattern.subject = matches1->object;
423 pattern.predicate = (char*)(LADSPA_BASE "hasLabel");
424 pattern.object = 0;
425 pattern.object_type = lrdf_literal;
427 lrdf_statement* matches2 = lrdf_matches (&pattern);
428 lrdf_free_statements(matches1);
430 if (!matches2) {
431 return ("Unknown");
434 string label = matches2->object;
435 lrdf_free_statements(matches2);
437 /* Kludge LADSPA class names to be singular and match LV2 class names.
438 This avoids duplicate plugin menus for every class, which is necessary
439 to make the plugin category menu at all usable, but is obviously a
440 filthy kludge.
442 In the short term, lrdf could be updated so the labels match and a new
443 release made. To support both specs, we should probably be mapping the
444 URIs to the same category in code and perhaps tweaking that hierarchy
445 dynamically to suit the user. Personally, I (drobilla) think that time
446 is better spent replacing the little-used LRDF.
448 In the longer term, we will abandon LRDF entirely in favour of LV2 and
449 use that class hierarchy. Aside from fixing this problem properly, that
450 will also allow for translated labels. SWH plugins have been LV2 for
451 ages; TAP needs porting. I don't know of anything else with LRDF data.
453 if (label == "Utilities") {
454 return "Utility";
455 } else if (label == "Pitch shifters") {
456 return "Pitch Shifter";
457 } else if (label != "Dynamics" && label != "Chorus"
458 &&label[label.length() - 1] == 's'
459 && label[label.length() - 2] != 's') {
460 return label.substr(0, label.length() - 1);
461 } else {
462 return label;
466 #ifdef LV2_SUPPORT
467 void
468 PluginManager::lv2_refresh ()
470 delete _lv2_plugin_info;
471 _lv2_plugin_info = LV2PluginInfo::discover();
473 #endif
475 #ifdef HAVE_AUDIOUNITS
476 void
477 PluginManager::au_refresh ()
479 delete _au_plugin_info;
480 _au_plugin_info = AUPluginInfo::discover();
483 #endif
485 #ifdef VST_SUPPORT
487 void
488 PluginManager::vst_refresh ()
490 if (_vst_plugin_info)
491 _vst_plugin_info->clear ();
492 else
493 _vst_plugin_info = new ARDOUR::PluginInfoList();
495 if (vst_path.length() == 0) {
496 vst_path = "/usr/local/lib/vst:/usr/lib/vst";
499 vst_discover_from_path (vst_path);
503 PluginManager::add_vst_directory (string path)
505 if (vst_discover_from_path (path) == 0) {
506 vst_path += ':';
507 vst_path += path;
508 return 0;
510 return -1;
513 static bool vst_filter (const string& str, void *arg)
515 /* Not a dotfile, has a prefix before a period, suffix is "dll" */
517 return str[0] != '.' && (str.length() > 4 && str.find (".dll") == (str.length() - 4));
521 PluginManager::vst_discover_from_path (string path)
523 PathScanner scanner;
524 vector<string *> *plugin_objects;
525 vector<string *>::iterator x;
526 int ret = 0;
528 info << "detecting VST plugins along " << path << endmsg;
530 plugin_objects = scanner (vst_path, vst_filter, 0, true, true);
532 if (plugin_objects) {
533 for (x = plugin_objects->begin(); x != plugin_objects->end (); ++x) {
534 vst_discover (**x);
538 vector_delete (plugin_objects);
539 return ret;
543 PluginManager::vst_discover (string path)
545 FSTInfo* finfo;
546 char buf[32];
548 if ((finfo = fst_get_info (const_cast<char *> (path.c_str()))) == 0) {
549 warning << "Cannot get VST information from " << path << endmsg;
550 return -1;
553 if (!finfo->canProcessReplacing) {
554 warning << string_compose (_("VST plugin %1 does not support processReplacing, and so cannot be used in ardour at this time"),
555 finfo->name)
556 << endl;
559 PluginInfoPtr info(new VSTPluginInfo);
561 /* what a joke freeware VST is */
563 if (!strcasecmp ("The Unnamed plugin", finfo->name)) {
564 info->name = PBD::basename_nosuffix (path);
565 } else {
566 info->name = finfo->name;
570 snprintf (buf, sizeof (buf), "%d", finfo->UniqueID);
571 info->unique_id = buf;
572 info->category = "VST";
573 info->path = path;
574 info->creator = finfo->creator;
575 info->index = 0;
576 info->n_inputs.set_audio (finfo->numInputs);
577 info->n_outputs.set_audio (finfo->numOutputs);
578 info->n_inputs.set_midi (finfo->wantMidi ? 1 : 0);
579 info->type = ARDOUR::VST;
581 _vst_plugin_info->push_back (info);
582 fst_free_info (finfo);
584 return 0;
587 #endif // VST_SUPPORT
589 PluginManager::PluginStatusType
590 PluginManager::get_status (const PluginInfoPtr& pi)
592 PluginStatus ps (pi->type, pi->unique_id);
593 PluginStatusList::const_iterator i = find (statuses.begin(), statuses.end(), ps);
594 if (i == statuses.end() ) {
595 return Normal;
596 } else {
597 return i->status;
601 void
602 PluginManager::save_statuses ()
604 ofstream ofs;
605 sys::path path = user_config_directory();
606 path /= "plugin_statuses";
608 ofs.open (path.to_string().c_str(), ios_base::openmode (ios::out|ios::trunc));
610 if (!ofs) {
611 return;
614 for (PluginStatusList::iterator i = statuses.begin(); i != statuses.end(); ++i) {
615 switch ((*i).type) {
616 case LADSPA:
617 ofs << "LADSPA";
618 break;
619 case AudioUnit:
620 ofs << "AudioUnit";
621 break;
622 case LV2:
623 ofs << "LV2";
624 break;
625 case VST:
626 ofs << "VST";
627 break;
630 ofs << ' ';
632 switch ((*i).status) {
633 case Normal:
634 ofs << "Normal";
635 break;
636 case Favorite:
637 ofs << "Favorite";
638 break;
639 case Hidden:
640 ofs << "Hidden";
641 break;
644 ofs << ' ';
645 ofs << (*i).unique_id;;
646 ofs << endl;
649 ofs.close ();
652 void
653 PluginManager::load_statuses ()
655 sys::path path = user_config_directory();
656 path /= "plugin_statuses";
657 ifstream ifs (path.to_string().c_str());
659 if (!ifs) {
660 return;
663 std::string stype;
664 std::string sstatus;
665 std::string id;
666 PluginType type;
667 PluginStatusType status;
668 char buf[1024];
670 while (ifs) {
672 ifs >> stype;
673 if (!ifs) {
674 break;
678 ifs >> sstatus;
679 if (!ifs) {
680 break;
684 /* rest of the line is the plugin ID */
686 ifs.getline (buf, sizeof (buf), '\n');
687 if (!ifs) {
688 break;
691 if (sstatus == "Normal") {
692 status = Normal;
693 } else if (sstatus == "Favorite") {
694 status = Favorite;
695 } else if (sstatus == "Hidden") {
696 status = Hidden;
697 } else {
698 error << string_compose (_("unknown plugin status type \"%1\" - all entries ignored"), sstatus)
699 << endmsg;
700 statuses.clear ();
701 break;
704 if (stype == "LADSPA") {
705 type = LADSPA;
706 } else if (stype == "AudioUnit") {
707 type = AudioUnit;
708 } else if (stype == "LV2") {
709 type = LV2;
710 } else if (stype == "VST") {
711 type = VST;
712 } else {
713 error << string_compose (_("unknown plugin type \"%1\" - ignored"), stype)
714 << endmsg;
715 continue;
718 id = buf;
719 strip_whitespace_edges (id);
720 set_status (type, id, status);
723 ifs.close ();
726 void
727 PluginManager::set_status (PluginType t, string id, PluginStatusType status)
729 PluginStatus ps (t, id, status);
730 statuses.erase (ps);
732 if (status == Normal) {
733 return;
736 statuses.insert (ps);
739 ARDOUR::PluginInfoList&
740 PluginManager::vst_plugin_info ()
742 #ifdef VST_SUPPORT
743 if (!_vst_plugin_info)
744 vst_refresh();
745 return *_vst_plugin_info;
746 #else
747 return _empty_plugin_info;
748 #endif
751 ARDOUR::PluginInfoList&
752 PluginManager::ladspa_plugin_info ()
754 if (!_ladspa_plugin_info)
755 ladspa_refresh();
756 return *_ladspa_plugin_info;
759 ARDOUR::PluginInfoList&
760 PluginManager::lv2_plugin_info ()
762 #ifdef LV2_SUPPORT
763 if (!_lv2_plugin_info)
764 lv2_refresh();
765 return *_lv2_plugin_info;
766 #else
767 return _empty_plugin_info;
768 #endif
771 ARDOUR::PluginInfoList&
772 PluginManager::au_plugin_info ()
774 #ifdef HAVE_AUDIOUNITS
775 if (!_au_plugin_info)
776 au_refresh();
777 return *_au_plugin_info;
778 #else
779 return _empty_plugin_info;
780 #endif