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 #include "pbd/basename.h"
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"
52 #include "ardour/lv2_plugin.h"
56 #include "ardour/vst_plugin.h"
59 #ifdef HAVE_AUDIOUNITS
60 #include "ardour/audio_unit.h"
61 #include <Carbon/Carbon.h>
64 #include "pbd/error.h"
65 #include "pbd/stl_delete.h"
69 using namespace ARDOUR
;
73 PluginManager
* PluginManager::_manager
= 0;
75 PluginManager::PluginManager ()
77 , _ladspa_plugin_info(0)
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
;
94 if ((s
= getenv ("LADSPA_RDF_PATH"))){
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();
105 if (Config
->get_use_vst()) {
108 #endif /* VST_SUPPORT */
110 if ((s
= getenv ("LADSPA_PATH"))) {
114 if ((s
= getenv ("VST_PATH"))) {
116 } else if ((s
= getenv ("VST_PLUGINS"))) {
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()
146 PluginManager::refresh ()
153 if (Config
->get_use_vst()) {
156 #endif // VST_SUPPORT
157 #ifdef HAVE_AUDIOUNITS
161 PluginListChanged (); /* EMIT SIGNAL */
165 PluginManager::ladspa_refresh ()
167 if (_ladspa_plugin_info
)
168 _ladspa_plugin_info
->clear ();
170 _ladspa_plugin_info
= new ARDOUR::PluginInfoList ();
172 static const char *standard_paths
[] = {
173 "/usr/local/lib64/ladspa",
174 "/usr/local/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.
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
])]) {
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') {
202 if (!ladspa_path
.empty())
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) {
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*/)
235 vector
<string
*> *plugin_objects
;
236 vector
<string
*>::iterator x
;
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
);
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)));
261 PluginManager::add_ladspa_presets()
263 add_presets ("ladspa");
267 PluginManager::add_vst_presets()
272 PluginManager::add_presets(string domain
)
276 vector
<string
*> *presets
;
277 vector
<string
*>::iterator x
;
280 if ((envvar
= getenv ("HOME")) == 0) {
284 string path
= string_compose("%1/.%2/rdf", envvar
, domain
);
285 presets
= scanner (path
, rdf_filter
, 0, true, true);
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
);
300 PluginManager::add_lrdf_data (const string
&path
)
303 vector
<string
*>* rdf_files
;
304 vector
<string
*>::iterator x
;
306 rdf_files
= scanner (path
, rdf_filter
, 0, true, true);
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
)
325 const LADSPA_Descriptor
*descriptor
;
326 LADSPA_Descriptor_Function dfunc
;
329 if ((module
= dlopen (path
.c_str(), RTLD_NOW
)) == 0) {
330 error
<< string_compose(_("LADSPA: cannot load module \"%1\" (%2)"), path
, dlerror()) << endmsg
;
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
;
343 for (uint32_t i
= 0; ; ++i
) {
344 if ((descriptor
= dfunc (i
)) == 0) {
348 if (!ladspa_plugin_whitelist
.empty()) {
349 if (find (ladspa_plugin_whitelist
.begin(), ladspa_plugin_whitelist
.end(), descriptor
->UniqueID
) == ladspa_plugin_whitelist
.end()) {
354 PluginInfoPtr
info(new LadspaPluginInfo
);
355 info
->name
= descriptor
->Name
;
356 info
->category
= get_ladspa_category(descriptor
->UniqueID
);
357 info
->creator
= descriptor
->Maker
;
360 info
->n_inputs
= ChanCount();
361 info
->n_outputs
= ChanCount();
362 info
->type
= ARDOUR::LADSPA
;
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.
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
)){
394 _ladspa_plugin_info
->push_back (info
);
398 // GDB WILL NOT LIKE YOU IF YOU DO THIS
405 PluginManager::get_ladspa_category (uint32_t plugin_id
)
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
;
414 pattern
.object_type
= lrdf_uri
;
416 lrdf_statement
* matches1
= lrdf_matches (&pattern
);
422 pattern
.subject
= matches1
->object
;
423 pattern
.predicate
= (char*)(LADSPA_BASE
"hasLabel");
425 pattern
.object_type
= lrdf_literal
;
427 lrdf_statement
* matches2
= lrdf_matches (&pattern
);
428 lrdf_free_statements(matches1
);
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
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") {
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);
468 PluginManager::lv2_refresh ()
470 delete _lv2_plugin_info
;
471 _lv2_plugin_info
= LV2PluginInfo::discover();
475 #ifdef HAVE_AUDIOUNITS
477 PluginManager::au_refresh ()
479 delete _au_plugin_info
;
480 _au_plugin_info
= AUPluginInfo::discover();
488 PluginManager::vst_refresh ()
490 if (_vst_plugin_info
)
491 _vst_plugin_info
->clear ();
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) {
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
)
524 vector
<string
*> *plugin_objects
;
525 vector
<string
*>::iterator x
;
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
) {
538 vector_delete (plugin_objects
);
543 PluginManager::vst_discover (string path
)
548 if ((finfo
= fst_get_info (const_cast<char *> (path
.c_str()))) == 0) {
549 warning
<< "Cannot get VST information from " << path
<< endmsg
;
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"),
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
);
566 info
->name
= finfo
->name
;
570 snprintf (buf
, sizeof (buf
), "%d", finfo
->UniqueID
);
571 info
->unique_id
= buf
;
572 info
->category
= "VST";
574 info
->creator
= finfo
->creator
;
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
);
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() ) {
602 PluginManager::save_statuses ()
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
));
614 for (PluginStatusList::iterator i
= statuses
.begin(); i
!= statuses
.end(); ++i
) {
632 switch ((*i
).status
) {
645 ofs
<< (*i
).unique_id
;;
653 PluginManager::load_statuses ()
655 sys::path path
= user_config_directory();
656 path
/= "plugin_statuses";
657 ifstream
ifs (path
.to_string().c_str());
667 PluginStatusType status
;
684 /* rest of the line is the plugin ID */
686 ifs
.getline (buf
, sizeof (buf
), '\n');
691 if (sstatus
== "Normal") {
693 } else if (sstatus
== "Favorite") {
695 } else if (sstatus
== "Hidden") {
698 error
<< string_compose (_("unknown plugin status type \"%1\" - all entries ignored"), sstatus
)
704 if (stype
== "LADSPA") {
706 } else if (stype
== "AudioUnit") {
708 } else if (stype
== "LV2") {
710 } else if (stype
== "VST") {
713 error
<< string_compose (_("unknown plugin type \"%1\" - ignored"), stype
)
719 strip_whitespace_edges (id
);
720 set_status (type
, id
, status
);
727 PluginManager::set_status (PluginType t
, string id
, PluginStatusType status
)
729 PluginStatus
ps (t
, id
, status
);
732 if (status
== Normal
) {
736 statuses
.insert (ps
);
739 ARDOUR::PluginInfoList
&
740 PluginManager::vst_plugin_info ()
743 if (!_vst_plugin_info
)
745 return *_vst_plugin_info
;
747 return _empty_plugin_info
;
751 ARDOUR::PluginInfoList
&
752 PluginManager::ladspa_plugin_info ()
754 if (!_ladspa_plugin_info
)
756 return *_ladspa_plugin_info
;
759 ARDOUR::PluginInfoList
&
760 PluginManager::lv2_plugin_info ()
763 if (!_lv2_plugin_info
)
765 return *_lv2_plugin_info
;
767 return _empty_plugin_info
;
771 ARDOUR::PluginInfoList
&
772 PluginManager::au_plugin_info ()
774 #ifdef HAVE_AUDIOUNITS
775 if (!_au_plugin_info
)
777 return *_au_plugin_info
;
779 return _empty_plugin_info
;