/* Copyright (C) 2000-2002 Paul Davis This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include // so libraptor doesn't complain #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_AUDIOUNITS #include #endif #ifdef HAVE_SLV2 #include #endif #include #include "i18n.h" #include using namespace ARDOUR; using namespace PBD; sigc::signal Plugin::PresetFileExists; Plugin::Plugin (AudioEngine& e, Session& s) : _engine (e), _session (s) { } Plugin::Plugin (const Plugin& other) : _engine (other._engine), _session (other._session), _info (other._info) { } void Plugin::setup_controls () { uint32_t port_cnt = parameter_count(); /* set up a vector of null pointers for the controls. we'll fill this in on an as-needed basis. */ controls.assign (port_cnt, (PortControllable*) 0); } Plugin::~Plugin () { for (vector::iterator i = controls.begin(); i != controls.end(); ++i) { if (*i) { delete *i; } } } void Plugin::make_nth_control (uint32_t n, const XMLNode& node) { if (controls[n]) { /* already constructed */ return; } Plugin::ParameterDescriptor desc; get_parameter_descriptor (n, desc); controls[n] = new PortControllable (node, *this, n, desc.lower, desc.upper, desc.toggled, desc.logarithmic); } Controllable * Plugin::get_nth_control (uint32_t n, bool do_not_create) { if (n >= parameter_count()) { return 0; } if (controls[n] == 0 && !do_not_create) { Plugin::ParameterDescriptor desc; get_parameter_descriptor (n, desc); controls[n] = new PortControllable (describe_parameter (n), *this, n, desc.lower, desc.upper, desc.toggled, desc.logarithmic); } return controls[n]; } Plugin::PortControllable::PortControllable (string name, Plugin& p, uint32_t port_id, float low, float up, bool t, bool loga) : Controllable (name), plugin (p), absolute_port (port_id) { toggled = t; logarithmic = loga; lower = low; upper = up; range = upper - lower; } Plugin::PortControllable::PortControllable (const XMLNode& node, Plugin& p, uint32_t port_id, float low, float up, bool t, bool loga) : Controllable (node), plugin (p), absolute_port (port_id) { toggled = t; logarithmic = loga; lower = low; upper = up; range = upper - lower; } void Plugin::PortControllable::set_value (float value) { if (toggled) { if (value > 0.5) { value = 1.0; } else { value = 0.0; } } else { if (!logarithmic) { value = lower + (range * value); } else { float _lower = 0.0f; if (lower > 0.0f) { _lower = log(lower); } value = exp(_lower + log(range) * value); } } plugin.set_parameter (absolute_port, value); } float Plugin::PortControllable::get_value (void) const { float val = plugin.get_parameter (absolute_port); if (toggled) { return val; } else { if (logarithmic) { val = log(val); } return ((val - lower) / range); } } vector Plugin::get_presets() { vector labels; uint32_t id; std::string unique (unique_id()); /* XXX problem: AU plugins don't have numeric ID's. Solution: they have a different method of providing presets. XXX sub-problem: implement it. */ if (!isdigit (unique[0])) { return labels; } id = atol (unique.c_str()); lrdf_uris* set_uris = lrdf_get_setting_uris(id); if (set_uris) { for (uint32_t i = 0; i < (uint32_t) set_uris->count; ++i) { if (char* label = lrdf_get_label(set_uris->items[i])) { labels.push_back(label); presets[label] = set_uris->items[i]; } } lrdf_free_uris(set_uris); } // GTK2FIX find an equivalent way to do this with a vector (needed by GUI apis) // labels.unique(); return labels; } bool Plugin::load_preset(const string preset_label) { lrdf_defaults* defs = lrdf_get_setting_values(presets[preset_label].c_str()); if (defs) { for (uint32_t i = 0; i < (uint32_t) defs->count; ++i) { // The defs->items[i].pid < defs->count check is to work around // a bug in liblrdf that saves invalid values into the presets file. if (((uint32_t) defs->items[i].pid < (uint32_t) defs->count) && parameter_is_input (defs->items[i].pid)) { set_parameter(defs->items[i].pid, defs->items[i].value); } } lrdf_free_setting_values(defs); } return true; } bool Plugin::save_preset (string name, string domain) { lrdf_portvalue portvalues[parameter_count()]; lrdf_defaults defaults; uint32_t id; std::string unique (unique_id()); /* XXX problem: AU plugins don't have numeric ID's. Solution: they have a different method of providing/saving presets. XXX sub-problem: implement it. */ if (!isdigit (unique[0])) { return false; } id = atol (unique.c_str()); defaults.count = parameter_count(); defaults.items = portvalues; for (uint32_t i = 0; i < parameter_count(); ++i) { if (parameter_is_input (i)) { portvalues[i].pid = i; portvalues[i].value = get_parameter(i); } } char* envvar; if ((envvar = getenv ("HOME")) == 0) { warning << _("Could not locate HOME. Preset not saved.") << endmsg; return false; } string source(string_compose("file:%1/.%2/rdf/ardour-presets.n3", envvar, domain)); free(lrdf_add_preset(source.c_str(), name.c_str(), id, &defaults)); string path = string_compose("%1/.%2", envvar, domain); if (g_mkdir_with_parents (path.c_str(), 0775)) { warning << string_compose(_("Could not create %1. Preset not saved. (%2)"), path, strerror(errno)) << endmsg; return false; } path += "/rdf"; if (g_mkdir_with_parents (path.c_str(), 0775)) { warning << string_compose(_("Could not create %1. Preset not saved. (%2)"), path, strerror(errno)) << endmsg; return false; } if (lrdf_export_by_source(source.c_str(), source.substr(5).c_str())) { warning << string_compose(_("Error saving presets file %1."), source) << endmsg; return false; } return true; } PluginPtr ARDOUR::find_plugin(Session& session, string identifier, PluginType type) { PluginManager *mgr = PluginManager::the_manager(); PluginInfoList plugs; switch (type) { case ARDOUR::LADSPA: plugs = mgr->ladspa_plugin_info(); break; #ifdef HAVE_SLV2 case ARDOUR::LV2: plugs = mgr->lv2_plugin_info(); break; #endif #ifdef VST_SUPPORT case ARDOUR::VST: plugs = mgr->vst_plugin_info(); break; #endif #ifdef HAVE_AUDIOUNITS case ARDOUR::AudioUnit: /* Ardour before 2.8.5 stored identifiers using a broken function provided by Apple (StringForOSType()) that couldn't properly handle some bytes stored in some plugins' multi-character literal identifiers. Ardour 2.8.5 switched to use a modified version of this function, but one that was still problematic and not backwards compatible. So, if this is an AU and we didn't find it above, fix up the identifier we are looking for and check again. */ { std::string fixed = AUPlugin::maybe_fix_broken_au_id (identifier); if (fixed.empty()) { error << string_compose (_("This session contains an AU plugin whose ID cannot be understood - ignored (%1)"), identifier) << endmsg; return PluginPtr ((Plugin*) 0); } identifier = fixed; } plugs = mgr->au_plugin_info(); break; #endif default: return PluginPtr ((Plugin *) 0); } PluginInfoList::iterator i; for (i = plugs.begin(); i != plugs.end(); ++i) { if (identifier == (*i)->unique_id){ return (*i)->load (session); } } #ifdef VST_SUPPORT /* hmm, we didn't find it. could be because in older versions of Ardour. we used to store the name of a VST plugin, not its unique ID. so try again. */ switch (type) { case ARDOUR::VST: for (i = plugs.begin(); i != plugs.end(); ++i) { if (identifier == (*i)->name){ return (*i)->load (session); } } break; default: break; } #endif return PluginPtr ((Plugin*) 0); } int32_t Plugin::configure_io (int32_t in, int32_t out) { /* parent Plugin class assumes static output stream count. Derived classes can override. */ Glib::Mutex::Lock em (_session.engine().process_lock()); IO::MoreOutputs (output_streams()); return 0; } int32_t Plugin::can_do (int32_t in, int32_t& out) { int32_t outputs = get_info()->n_outputs; int32_t inputs = get_info()->n_inputs; if (inputs == 0) { /* instrument plugin, always legal, but it throws away any existing active streams. */ out = outputs; return 1; } if (outputs == 1 && inputs == 1) { /* mono plugin, replicate as needed */ out = in; return in; } if (inputs == in) { /* exact match */ out = outputs; return 1; } if ((inputs < in) && (inputs % in == 0)) { /* number of inputs is a factor of the requested input configuration, so we can replicate. */ int nplugs = in/inputs; out = outputs * nplugs; return nplugs; } /* sorry */ return -1; } uint32_t Plugin::output_streams () const { /* LADSPA & VST should not get here because they do not return negative i/o counts. */ return 0; } uint32_t Plugin::input_streams () const { /* LADSPA & VST should not get here because they do not return negative i/o counts. */ return 0; }