LV2 support.
[ardour.git] / libs / ardour / insert.cc
index f8650c7ee189bceafada58646c292b1ea7d039cb..eb0576b46e583305f82a06a0d12e858ef43316e5 100644 (file)
 #include <ardour/route.h>
 #include <ardour/ladspa_plugin.h>
 
+#ifdef HAVE_SLV2
+#include <ardour/lv2_plugin.h>
+#endif
+
 #ifdef VST_SUPPORT
 #include <ardour/vst_plugin.h>
 #endif
@@ -75,7 +79,7 @@ PluginInsert::PluginInsert (Session& s, boost::shared_ptr<Plugin> plug, Placemen
        
        init ();
 
-       {
+       if (_plugins[0]->fixed_io()) {
                Glib::Mutex::Lock em (_session.engine().process_lock());
                IO::MoreOutputs (output_streams ());
        }
@@ -94,7 +98,7 @@ PluginInsert::PluginInsert (Session& s, const XMLNode& node)
 
        _plugins[0]->ParameterChanged.connect (mem_fun (*this, &PluginInsert::parameter_changed));
 
-       {
+       if (_plugins[0]->fixed_io()) {
                Glib::Mutex::Lock em (_session.engine().process_lock());
                IO::MoreOutputs (output_streams());
        }
@@ -166,7 +170,7 @@ PluginInsert::~PluginInsert ()
 void
 PluginInsert::automation_list_creation_callback (uint32_t which, AutomationList& alist)
 {
-  alist.automation_state_changed.connect (sigc::bind (mem_fun (*this, &PluginInsert::auto_state_changed), (which)));
+       alist.automation_state_changed.connect (sigc::bind (mem_fun (*this, &PluginInsert::auto_state_changed), (which)));
 }
 
 void
@@ -182,13 +186,24 @@ PluginInsert::auto_state_changed (uint32_t which)
 uint32_t
 PluginInsert::output_streams() const
 {
-       return _plugins[0]->get_info()->n_outputs * _plugins.size();
+       int32_t out = _plugins[0]->get_info()->n_outputs;
+
+       if (out < 0) {
+               return _plugins[0]->output_streams ();
+       } else {
+               return out * _plugins.size();
+       }
 }
 
 uint32_t
 PluginInsert::input_streams() const
 {
-       return _plugins[0]->get_info()->n_inputs * _plugins.size();
+       int32_t in = _plugins[0]->get_info()->n_inputs;
+       if (in < 0) {
+               return _plugins[0]->input_streams ();
+       } else {
+               return in * _plugins.size();
+       }
 }
 
 uint32_t
@@ -366,12 +381,17 @@ PluginInsert::run (vector<Sample *>& bufs, uint32_t nbufs, nframes_t nframes, nf
                uint32_t in = _plugins[0]->get_info()->n_inputs;
                uint32_t out = _plugins[0]->get_info()->n_outputs;
 
-               if (out > in) {
-
-                       /* not active, but something has make up for any channel count increase */
+               if (in < 0 || out < 0) {
                        
-                       for (uint32_t n = out - in; n < out; ++n) {
-                               memcpy (bufs[n], bufs[in - 1], sizeof (Sample) * nframes);
+               } else {
+
+                       if (out > in) {
+                               
+                               /* not active, but something has make up for any channel count increase */
+                               
+                               for (uint32_t n = out - in; n < out; ++n) {
+                                       memcpy (bufs[n], bufs[in - 1], sizeof (Sample) * nframes);
+                               }
                        }
                }
        }
@@ -499,6 +519,9 @@ boost::shared_ptr<Plugin>
 PluginInsert::plugin_factory (boost::shared_ptr<Plugin> other)
 {
        boost::shared_ptr<LadspaPlugin> lp;
+#ifdef HAVE_SLV2
+       boost::shared_ptr<LV2Plugin> lv2p;
+#endif
 #ifdef VST_SUPPORT
        boost::shared_ptr<VSTPlugin> vp;
 #endif
@@ -508,6 +531,10 @@ PluginInsert::plugin_factory (boost::shared_ptr<Plugin> other)
 
        if ((lp = boost::dynamic_pointer_cast<LadspaPlugin> (other)) != 0) {
                return boost::shared_ptr<Plugin> (new LadspaPlugin (*lp));
+#ifdef HAVE_SLV2
+       } else if ((lv2p = boost::dynamic_pointer_cast<LV2Plugin> (other)) != 0) {
+               return boost::shared_ptr<Plugin> (new LV2Plugin (*lv2p));
+#endif
 #ifdef VST_SUPPORT
        } else if ((vp = boost::dynamic_pointer_cast<VSTPlugin> (other)) != 0) {
                return boost::shared_ptr<Plugin> (new VSTPlugin (*vp));
@@ -528,7 +555,14 @@ PluginInsert::plugin_factory (boost::shared_ptr<Plugin> other)
 int32_t
 PluginInsert::compute_output_streams (int32_t cnt) const
 {
-       return _plugins[0]->get_info()->n_outputs * cnt;
+       int32_t outputs;
+
+       if ((outputs = _plugins[0]->get_info()->n_outputs) < 0) {
+               // have to ask the plugin itself, because it has flexible I/O
+               return _plugins[0]->compute_output_streams (cnt);
+       }
+
+       return outputs * cnt;
 }
 
 int32_t
@@ -543,6 +577,12 @@ PluginInsert::can_support_input_configuration (int32_t in) const
        int32_t outputs = _plugins[0]->get_info()->n_outputs;
        int32_t inputs = _plugins[0]->get_info()->n_inputs;
 
+       if (outputs < 0 || inputs < 0) {
+               /* have to ask the plugin because its got reconfigurable I/O
+                */
+               return _plugins[0]->can_support_input_configuration (in);
+       }
+
        if (inputs == 0) {
 
                /* instrument plugin, always legal, but it throws
@@ -591,16 +631,24 @@ PluginInsert::state (bool full)
        node->add_child_nocopy (Redirect::state (full));
 
        node->add_property ("type", _plugins[0]->state_node_name());
-       snprintf(buf, sizeof(buf), "%s", _plugins[0]->name());
-       node->add_property("id", string(buf));
-       if (_plugins[0]->state_node_name() == "ladspa") {
-               char buf[32];
-               snprintf (buf, sizeof (buf), "%ld", _plugins[0]->get_info()->unique_id); 
-               node->add_property("unique-id", string(buf));
-       }
+       node->add_property("unique-id", _plugins[0]->unique_id());
        node->add_property("count", string_compose("%1", _plugins.size()));
        node->add_child_nocopy (_plugins[0]->get_state());
 
+       /* add controllables */
+
+       XMLNode* control_node = new XMLNode (X_("controls"));
+
+       for (uint32_t x = 0; x < _plugins[0]->parameter_count(); ++x) {
+               Controllable* c = _plugins[0]->get_nth_control (x, true);
+               if (c) {
+                       XMLNode& controllable_state (c->get_state());
+                       controllable_state.add_property ("parameter", to_string (x, std::dec));
+                       control_node->add_child_nocopy (controllable_state);
+               }
+       }
+       node->add_child_nocopy (*control_node);
+
        /* add port automation state */
        XMLNode *autonode = new XMLNode(port_automation_node_name);
        set<uint32_t> automatable = _plugins[0]->automatable();
@@ -627,7 +675,6 @@ PluginInsert::set_state(const XMLNode& node)
        XMLNodeIterator niter;
        XMLPropertyList plist;
        const XMLProperty *prop;
-       long unique = 0;
        ARDOUR::PluginType type;
 
        if ((prop = node.property ("type")) == 0) {
@@ -637,8 +684,12 @@ PluginInsert::set_state(const XMLNode& node)
 
        if (prop->value() == X_("ladspa") || prop->value() == X_("Ladspa")) { /* handle old school sessions */
                type = ARDOUR::LADSPA;
+       } else if (prop->value() == X_("lv2")) {
+               type = ARDOUR::LV2;
        } else if (prop->value() == X_("vst")) {
                type = ARDOUR::VST;
+       } else if (prop->value() == X_("audiounit")) {
+               type = ARDOUR::AudioUnit;
        } else {
                error << string_compose (_("unknown plugin type %1 in plugin insert state"),
                                  prop->value())
@@ -647,22 +698,27 @@ PluginInsert::set_state(const XMLNode& node)
        }
 
        prop = node.property ("unique-id");
-       if (prop != 0) {
-               unique = atol(prop->value().c_str());
-       }
+       if (prop == 0) {
+#ifdef VST_SUPPORT
+               /* older sessions contain VST plugins with only an "id" field.
+                */
+               
+               if (type == ARDOUR::VST) {
+                       if (prop = node.property ("id")) {
+                       }
+               }
+#endif         
+               /* recheck  */
 
-       if ((prop = node.property ("id")) == 0) {
-               error << _("XML node describing insert is missing the `id' field") << endmsg;
-               return -1;
+               if (prop == 0) {
+                       error << _("Plugin has no unique ID field") << endmsg;
+                       return -1;
+               }
        }
 
        boost::shared_ptr<Plugin> plugin;
        
-       if (unique != 0) {
-               plugin = find_plugin (_session, "", unique, type);      
-       } else {
-               plugin = find_plugin (_session, prop->value(), 0, type);        
-       }
+       plugin = find_plugin (_session, prop->value(), type);   
 
        if (plugin == 0) {
                error << string_compose(_("Found a reference to a plugin (\"%1\") that is unknown.\n"
@@ -695,6 +751,11 @@ PluginInsert::set_state(const XMLNode& node)
                }
        } 
 
+       if (niter == nlist.end()) {
+               error << string_compose(_("XML node describing a plugin insert is missing the `%1' information"), plugin->state_node_name()) << endmsg;
+               return -1;
+       }
+
        for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
                if ((*niter)->name() == Redirect::state_node_name) {
                        Redirect::set_state (**niter);
@@ -707,11 +768,30 @@ PluginInsert::set_state(const XMLNode& node)
                return -1;
        }
 
-       if (niter == nlist.end()) {
-               error << string_compose(_("XML node describing a plugin insert is missing the `%1' information"), plugin->state_node_name()) << endmsg;
-               return -1;
-       }
+       /* look for controllables node */
        
+       for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
+
+               if ((*niter)->name() != X_("controls")) {
+                       continue;
+               }
+               
+               XMLNodeList grandchildren ((*niter)->children());
+               XMLProperty* prop;
+               XMLNodeIterator gciter;
+               uint32_t param;
+               
+               for (gciter = grandchildren.begin(); gciter != grandchildren.end(); ++gciter) {
+                       if ((prop = (*gciter)->property (X_("parameter"))) != 0) {
+                               param = atoi (prop->value());
+                               /* force creation of controllable for this parameter */
+                               _plugins[0]->make_nth_control (param, **gciter);
+                       } 
+               }
+
+               break;
+       }
+               
        /* look for port automation node */
        
        for (niter = nlist.begin(); niter != nlist.end(); ++niter) {