Logo Search packages:      
Sourcecode: ardour version File versions  Download package

plugin.cc

/*
    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 <vector>
#include <string>

#include <cstdlib>
#include <cstdio> // so libraptor doesn't complain
#include <cmath>
#include <dirent.h>
#include <sys/stat.h>
#include <cerrno>

#include <lrdf.h>

#include <pbd/compose.h>
#include <pbd/error.h>
#include <pbd/pathscanner.h>
#include <pbd/xml++.h>
#include <pbd/stacktrace.h>

#include <ardour/ardour.h>
#include <ardour/session.h>
#include <ardour/audioengine.h>
#include <ardour/plugin.h>
#include <ardour/ladspa_plugin.h>
#include <ardour/plugin_manager.h>

#ifdef HAVE_AUDIOUNITS
#include <ardour/audio_unit.h>
#endif

#ifdef HAVE_SLV2
#include <ardour/lv2_plugin.h>
#endif

#include <pbd/stl_delete.h>

#include "i18n.h"
#include <locale.h>

using namespace ARDOUR;
using namespace PBD;

sigc::signal<bool> 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<PortControllable*>::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<string>
Plugin::get_presets()
{
      vector<string> 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;
}



Generated by  Doxygen 1.6.0   Back to index