prototype online self-automating LV2 plugin interface
[ardour.git] / libs / ardour / plugin_insert.cc
index 34745b7cabd933aea2f7b685dd6e2d5fffedf30f..c085f1f9cbb5255e0f00845cf98c65ac5db5ab4c 100644 (file)
@@ -33,6 +33,7 @@
 #include "ardour/debug.h"
 #include "ardour/event_type_map.h"
 #include "ardour/ladspa_plugin.h"
+#include "ardour/luaproc.h"
 #include "ardour/plugin.h"
 #include "ardour/plugin_insert.h"
 
@@ -250,7 +251,9 @@ PluginInsert::create_automatable_parameters ()
 
                        can_automate (param);
                        boost::shared_ptr<AutomationList> list(new AutomationList(param, desc));
-                       add_control (boost::shared_ptr<AutomationControl> (new PluginControl(this, param, desc, list)));
+                       boost::shared_ptr<AutomationControl> c (new PluginControl(this, param, desc, list));
+                       add_control (c);
+                       _plugins.front()->set_automation_control (i->id(), c);
                } else if (i->type() == PluginPropertyAutomation) {
                        Evoral::Parameter param(*i);
                        const ParameterDescriptor& desc = _plugins.front()->get_property_descriptor(param.id());
@@ -439,7 +442,9 @@ PluginInsert::connect_and_run (BufferSet& bufs, pframes_t nframes, framecnt_t of
        }
 
        for (Plugins::iterator i = _plugins.begin(); i != _plugins.end(); ++i) {
-               (*i)->connect_and_run(bufs, in_map, out_map, nframes, offset);
+               if ((*i)->connect_and_run(bufs, in_map, out_map, nframes, offset)) {
+                       deactivate ();
+               }
                for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
                        in_map.offset_to(*t, natural_input_streams().get(*t));
                        out_map.offset_to(*t, natural_output_streams().get(*t));
@@ -557,7 +562,7 @@ PluginInsert::automation_run (BufferSet& bufs, framepos_t start, pframes_t nfram
                return;
        }
 
-       if (!find_next_event (now, end, next_event) || requires_fixed_sized_buffers()) {
+       if (!find_next_event (now, end, next_event) || _plugins.front()->requires_fixed_sized_buffers()) {
 
                /* no events have a time within the relevant range */
 
@@ -660,7 +665,7 @@ PluginInsert::reset_parameters_to_default ()
                        continue;
                }
 
-               ac->set_value (dflt);
+               ac->set_value (dflt, Controllable::NoGroup);
        }
        return all;
 }
@@ -669,6 +674,7 @@ boost::shared_ptr<Plugin>
 PluginInsert::plugin_factory (boost::shared_ptr<Plugin> other)
 {
        boost::shared_ptr<LadspaPlugin> lp;
+       boost::shared_ptr<LuaProc> lua;
 #ifdef LV2_SUPPORT
        boost::shared_ptr<LV2Plugin> lv2p;
 #endif
@@ -684,6 +690,8 @@ 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));
+       } else if ((lua = boost::dynamic_pointer_cast<LuaProc> (other)) != 0) {
+               return boost::shared_ptr<Plugin> (new LuaProc (*lua));
 #ifdef LV2_SUPPORT
        } else if ((lv2p = boost::dynamic_pointer_cast<LV2Plugin> (other)) != 0) {
                return boost::shared_ptr<Plugin> (new LV2Plugin (*lv2p));
@@ -952,6 +960,7 @@ PluginInsert::state (bool full)
        node.add_child_nocopy (* _configured_in.state (X_("ConfiguredInput")));
        node.add_child_nocopy (* _configured_out.state (X_("ConfiguredOutput")));
 
+       _plugins[0]->set_insert_id(this->id());
        node.add_child_nocopy (_plugins[0]->get_state());
 
        for (Controls::iterator c = controls().begin(); c != controls().end(); ++c) {
@@ -975,8 +984,20 @@ PluginInsert::set_control_ids (const XMLNode& node, int version)
                if ((*iter)->name() == Controllable::xml_node_name) {
                        const XMLProperty* prop;
 
-                       if ((prop = (*iter)->property (X_("parameter"))) != 0) {
-                               uint32_t p = atoi (prop->value());
+                       uint32_t p = (uint32_t)-1;
+#ifdef LV2_SUPPORT
+                       if ((prop = (*iter)->property (X_("symbol"))) != 0) {
+                               boost::shared_ptr<LV2Plugin> lv2plugin = boost::dynamic_pointer_cast<LV2Plugin> (_plugins[0]);
+                               if (lv2plugin) {
+                                       p = lv2plugin->port_index(prop->value().c_str());
+                               }
+                       }
+#endif
+                       if (p == (uint32_t)-1 && (prop = (*iter)->property (X_("parameter"))) != 0) {
+                               p = atoi (prop->value());
+                       }
+
+                       if (p != (uint32_t)-1) {
 
                                /* this may create the new controllable */
 
@@ -1020,6 +1041,8 @@ PluginInsert::set_state(const XMLNode& node, int version)
                type = ARDOUR::LXVST;
        } else if (prop->value() == X_("audiounit")) {
                type = ARDOUR::AudioUnit;
+       } else if (prop->value() == X_("luaproc")) {
+               type = ARDOUR::Lua;
        } else {
                error << string_compose (_("unknown plugin type %1 in plugin insert state"),
                                  prop->value())
@@ -1081,6 +1104,15 @@ PluginInsert::set_state(const XMLNode& node, int version)
                return -1;
        }
 
+       if (type == ARDOUR::Lua) {
+               XMLNode *ls = node.child (plugin->state_node_name().c_str());
+               // we need to load the script to set the name and parameters.
+               boost::shared_ptr<LuaProc> lp = boost::dynamic_pointer_cast<LuaProc>(plugin);
+               if (ls && lp) {
+                       lp->set_script_from_state (*ls);
+               }
+       }
+
        // The name of the PluginInsert comes from the plugin, nothing else
        _name = plugin->get_info()->name;
 
@@ -1114,6 +1146,13 @@ PluginInsert::set_state(const XMLNode& node, int version)
 
        Processor::set_state (node, version);
 
+       PBD::ID new_id = this->id();
+       PBD::ID old_id = this->id();
+
+       if ((prop = node.property ("id")) != 0) {
+               old_id = prop->value ();
+       }
+
        for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
 
                /* find the node with the type-specific node name ("lv2", "ladspa", etc)
@@ -1123,7 +1162,27 @@ PluginInsert::set_state(const XMLNode& node, int version)
                if ((*niter)->name() == plugin->state_node_name()) {
 
                        for (Plugins::iterator i = _plugins.begin(); i != _plugins.end(); ++i) {
+                               /* Plugin state can include external files which are named after the ID.
+                                *
+                                * If regenerate_xml_or_string_ids() is set, the ID will already have
+                                * been changed, so we need to use the old ID from the XML to load the
+                                * state and then update the ID.
+                                *
+                                * When copying a plugin-state, route_ui takes care of of updating the ID,
+                                * but we need to call set_insert_id() to clear the cached plugin-state
+                                * and force a change.
+                                */
+                               if (!regenerate_xml_or_string_ids ()) {
+                                       (*i)->set_insert_id (new_id);
+                               } else {
+                                       (*i)->set_insert_id (old_id);
+                               }
+
                                (*i)->set_state (**niter, version);
+
+                               if (regenerate_xml_or_string_ids ()) {
+                                       (*i)->set_insert_id (new_id);
+                               }
                        }
 
                        break;
@@ -1167,6 +1226,13 @@ PluginInsert::update_id (PBD::ID id)
        }
 }
 
+void
+PluginInsert::set_state_dir (const std::string& d)
+{
+       // state() only saves the state of the first plugin
+       _plugins[0]->set_state_dir (d);
+}
+
 void
 PluginInsert::set_parameter_state_2X (const XMLNode& node, int version)
 {
@@ -1302,15 +1368,21 @@ PluginInsert::PluginControl::PluginControl (PluginInsert*                     p,
 
 /** @param val `user' value */
 void
-PluginInsert::PluginControl::set_value (double user_val)
+PluginInsert::PluginControl::set_value (double user_val, PBD::Controllable::GroupControlDisposition group_override)
 {
        if (writable()) {
-               set_value_unchecked (user_val);
+               _set_value (user_val, group_override);
        }
 }
-
 void
 PluginInsert::PluginControl::set_value_unchecked (double user_val)
+{
+       /* used only by automation playback */
+       _set_value (user_val, Controllable::NoGroup);
+}
+
+void
+PluginInsert::PluginControl::_set_value (double user_val, PBD::Controllable::GroupControlDisposition group_override)
 {
        /* FIXME: probably should be taking out some lock here.. */
 
@@ -1323,13 +1395,13 @@ PluginInsert::PluginControl::set_value_unchecked (double user_val)
                iasp->set_parameter (_list->parameter().id(), user_val);
        }
 
-       AutomationControl::set_value (user_val);
+       AutomationControl::set_value (user_val, group_override);
 }
 
 void
 PluginInsert::PluginControl::catch_up_with_external_value (double user_val)
 {
-       AutomationControl::set_value (user_val);
+       AutomationControl::set_value (user_val, Controllable::NoGroup);
 }
 
 XMLNode&
@@ -1340,6 +1412,12 @@ PluginInsert::PluginControl::get_state ()
        XMLNode& node (AutomationControl::get_state());
        ss << parameter().id();
        node.add_property (X_("parameter"), ss.str());
+#ifdef LV2_SUPPORT
+       boost::shared_ptr<LV2Plugin> lv2plugin = boost::dynamic_pointer_cast<LV2Plugin> (_plugin->_plugins[0]);
+       if (lv2plugin) {
+               node.add_property (X_("symbol"), lv2plugin->port_symbol (parameter().id()));
+       }
+#endif
 
        return node;
 }
@@ -1375,7 +1453,7 @@ PluginInsert::PluginPropertyControl::PluginPropertyControl (PluginInsert*
 }
 
 void
-PluginInsert::PluginPropertyControl::set_value (double user_val)
+PluginInsert::PluginPropertyControl::set_value (double user_val, PBD::Controllable::GroupControlDisposition /* group_override*/)
 {
        if (writable()) {
                set_value_unchecked (user_val);
@@ -1399,7 +1477,7 @@ PluginInsert::PluginPropertyControl::set_value_unchecked (double user_val)
        }
 
        _value = value;
-       AutomationControl::set_value(user_val);
+       AutomationControl::set_value (user_val, Controllable::NoGroup);
 }
 
 XMLNode&