LV2 support.
[ardour.git] / libs / ardour / insert.cc
index 1c73ef9d79c9a061eb15853f27e7c8c5e4c92015..eb0576b46e583305f82a06a0d12e858ef43316e5 100644 (file)
@@ -15,7 +15,6 @@
     along with this program; if not, write to the Free Software
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
-    $Id$
 */
 
 #include <string>
 #include <ardour/port.h>
 #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
+
+#ifdef HAVE_AUDIOUNITS
+#include <ardour/audio_unit.h>
+#endif
+
 #include <ardour/audioengine.h>
 #include <ardour/session.h>
+#include <ardour/types.h>
 
 #include "i18n.h"
 
 using namespace std;
 using namespace ARDOUR;
-//using namespace sigc;
+using namespace PBD;
 
-Insert::Insert(Session& s, Placement p)
-       : Redirect (s, s.next_insert_name(), p)
-{
-}
-
-
-Insert::Insert(Session& s, Placement p, int imin, int imax, int omin, int omax)
-       : Redirect (s, s.next_insert_name(), p, imin, imax, omin, omax)
+Insert::Insert(Session& s, string name, Placement p)
+       : Redirect (s, name, p)
 {
 }
 
-Insert::Insert(Session& s, string name, Placement p)
-       : Redirect (s, name, p)
+Insert::Insert(Session& s, string name, Placement p, int imin, int imax, int omin, int omax)
+       : Redirect (s, name, p, imin, imax, omin, omax)
 {
 }
 
@@ -62,21 +68,19 @@ Insert::Insert(Session& s, string name, Placement p)
 
 const string PluginInsert::port_automation_node_name = "PortAutomation";
 
-PluginInsert::PluginInsert (Session& s, Plugin& plug, Placement placement)
-       : Insert (s, plug.name(), placement)
+PluginInsert::PluginInsert (Session& s, boost::shared_ptr<Plugin> plug, Placement placement)
+       : Insert (s, plug->name(), placement)
 {
        /* the first is the master */
 
-       _plugins.push_back(&plug);
+       _plugins.push_back (plug);
 
        _plugins[0]->ParameterChanged.connect (mem_fun (*this, &PluginInsert::parameter_changed));
        
        init ();
 
-       save_state (_("initial state"));
-
-       {
-               LockMonitor em (_session.engine().process_lock(), __LINE__, __FILE__);
+       if (_plugins[0]->fixed_io()) {
+               Glib::Mutex::Lock em (_session.engine().process_lock());
                IO::MoreOutputs (output_streams ());
        }
 
@@ -92,24 +96,22 @@ PluginInsert::PluginInsert (Session& s, const XMLNode& node)
 
        set_automatable ();
 
-       save_state (_("initial state"));
-
        _plugins[0]->ParameterChanged.connect (mem_fun (*this, &PluginInsert::parameter_changed));
 
-       {
-               LockMonitor em (_session.engine().process_lock(), __LINE__, __FILE__);
+       if (_plugins[0]->fixed_io()) {
+               Glib::Mutex::Lock em (_session.engine().process_lock());
                IO::MoreOutputs (output_streams());
        }
 }
 
 PluginInsert::PluginInsert (const PluginInsert& other)
-       : Insert (other._session, other.plugin().name(), other.placement())
+       : Insert (other._session, other.plugin()->name(), other.placement())
 {
        uint32_t count = other._plugins.size();
 
        /* make as many copies as requested */
        for (uint32_t n = 0; n < count; ++n) {
-               _plugins.push_back (plugin_factory (other.plugin()));
+               _plugins.push_back (plugin_factory (other.plugin (n)));
        }
 
 
@@ -117,8 +119,6 @@ PluginInsert::PluginInsert (const PluginInsert& other)
 
        init ();
 
-       save_state (_("initial state"));
-
        RedirectCreated (this); /* EMIT SIGNAL */
 }
 
@@ -137,7 +137,7 @@ PluginInsert::set_count (uint32_t num)
                uint32_t diff = num - _plugins.size();
 
                for (uint32_t n = 0; n < diff; ++n) {
-                       _plugins.push_back (plugin_factory (*_plugins[0]));
+                       _plugins.push_back (plugin_factory (_plugins[0]));
 
                        if (require_state) {
                                /* XXX do something */
@@ -147,9 +147,7 @@ PluginInsert::set_count (uint32_t num)
        } else if (num < _plugins.size()) {
                uint32_t diff = _plugins.size() - num;
                for (uint32_t n= 0; n < diff; ++n) {
-                       Plugin * plug = _plugins.back();
                        _plugins.pop_back();
-                       delete plug;
                }
        }
 
@@ -166,19 +164,13 @@ PluginInsert::init ()
 
 PluginInsert::~PluginInsert ()
 {
-       GoingAway (this); /* EMIT SIGNAL */
-       
-       while (!_plugins.empty()) {
-               Plugin* p = _plugins.back();
-               _plugins.pop_back();
-               delete p;
-       }
+       GoingAway (); /* EMIT SIGNAL */
 }
 
 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
@@ -194,25 +186,36 @@ 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
 PluginInsert::natural_output_streams() const
 {
-       return _plugins[0]->get_info().n_outputs;
+       return _plugins[0]->get_info()->n_outputs;
 }
 
 uint32_t
 PluginInsert::natural_input_streams() const
 {
-       return _plugins[0]->get_info().n_inputs;
+       return _plugins[0]->get_info()->n_inputs;
 }
 
 bool
@@ -222,7 +225,7 @@ PluginInsert::is_generator() const
           a specific "instrument" flag, for example.
         */
 
-       return _plugins[0]->get_info().n_inputs == 0;
+       return _plugins[0]->get_info()->n_inputs == 0;
 }
 
 void
@@ -240,7 +243,7 @@ PluginInsert::set_automatable ()
 void
 PluginInsert::parameter_changed (uint32_t which, float val)
 {
-       vector<Plugin*>::iterator i = _plugins.begin();
+       vector<boost::shared_ptr<Plugin> >::iterator i = _plugins.begin();
 
        /* don't set the first plugin, just all the slaves */
 
@@ -253,9 +256,9 @@ PluginInsert::parameter_changed (uint32_t which, float val)
 }
 
 void
-PluginInsert::set_block_size (jack_nframes_t nframes)
+PluginInsert::set_block_size (nframes_t nframes)
 {
-       for (vector<Plugin*>::iterator i = _plugins.begin(); i != _plugins.end(); ++i) {
+       for (vector<boost::shared_ptr<Plugin> >::iterator i = _plugins.begin(); i != _plugins.end(); ++i) {
                (*i)->set_block_size (nframes);
        }
 }
@@ -263,7 +266,7 @@ PluginInsert::set_block_size (jack_nframes_t nframes)
 void
 PluginInsert::activate ()
 {
-       for (vector<Plugin*>::iterator i = _plugins.begin(); i != _plugins.end(); ++i) {
+       for (vector<boost::shared_ptr<Plugin> >::iterator i = _plugins.begin(); i != _plugins.end(); ++i) {
                (*i)->activate ();
        }
 }
@@ -271,13 +274,13 @@ PluginInsert::activate ()
 void
 PluginInsert::deactivate ()
 {
-       for (vector<Plugin*>::iterator i = _plugins.begin(); i != _plugins.end(); ++i) {
+       for (vector<boost::shared_ptr<Plugin> >::iterator i = _plugins.begin(); i != _plugins.end(); ++i) {
                (*i)->deactivate ();
        }
 }
 
 void
-PluginInsert::connect_and_run (vector<Sample*>& bufs, uint32_t nbufs, jack_nframes_t nframes, jack_nframes_t offset, bool with_auto, jack_nframes_t now)
+PluginInsert::connect_and_run (vector<Sample*>& bufs, uint32_t nbufs, nframes_t nframes, nframes_t offset, bool with_auto, nframes_t now)
 {
        int32_t in_index = 0;
        int32_t out_index = 0;
@@ -309,7 +312,7 @@ PluginInsert::connect_and_run (vector<Sample*>& bufs, uint32_t nbufs, jack_nfram
                }
        }
 
-       for (vector<Plugin*>::iterator i = _plugins.begin(); i != _plugins.end(); ++i) {
+       for (vector<boost::shared_ptr<Plugin> >::iterator i = _plugins.begin(); i != _plugins.end(); ++i) {
                (*i)->connect_and_run (bufs, nbufs, in_index, out_index, nframes, offset);
        }
 
@@ -317,7 +320,7 @@ PluginInsert::connect_and_run (vector<Sample*>& bufs, uint32_t nbufs, jack_nfram
 }
 
 void
-PluginInsert::automation_snapshot (jack_nframes_t now)
+PluginInsert::automation_snapshot (nframes_t now)
 {
        map<uint32_t,AutomationList*>::iterator li;
        
@@ -334,7 +337,7 @@ PluginInsert::automation_snapshot (jack_nframes_t now)
 }
 
 void
-PluginInsert::transport_stopped (jack_nframes_t now)
+PluginInsert::transport_stopped (nframes_t now)
 {
        map<uint32_t,AutomationList*>::iterator li;
 
@@ -349,7 +352,7 @@ PluginInsert::transport_stopped (jack_nframes_t now)
 }
 
 void
-PluginInsert::silence (jack_nframes_t nframes, jack_nframes_t offset)
+PluginInsert::silence (nframes_t nframes, nframes_t offset)
 {
        int32_t in_index = 0;
        int32_t out_index = 0;
@@ -357,15 +360,15 @@ PluginInsert::silence (jack_nframes_t nframes, jack_nframes_t offset)
        uint32_t n;
 
        if (active()) {
-               for (vector<Plugin*>::iterator i = _plugins.begin(); i != _plugins.end(); ++i) {
-                       n = (*i) -> get_info().n_inputs;
+               for (vector<boost::shared_ptr<Plugin> >::iterator i = _plugins.begin(); i != _plugins.end(); ++i) {
+                       n = (*i) -> get_info()->n_inputs;
                        (*i)->connect_and_run (_session.get_silent_buffers (n), n, in_index, out_index, nframes, offset);
                }
        }
 }
        
 void
-PluginInsert::run (vector<Sample *>& bufs, uint32_t nbufs, jack_nframes_t nframes, jack_nframes_t offset)
+PluginInsert::run (vector<Sample *>& bufs, uint32_t nbufs, nframes_t nframes, nframes_t offset)
 {
        if (active()) {
 
@@ -375,15 +378,20 @@ PluginInsert::run (vector<Sample *>& bufs, uint32_t nbufs, jack_nframes_t nframe
                        connect_and_run (bufs, nbufs, nframes, offset, false);
                }
        } else {
-               uint32_t in = _plugins[0]->get_info().n_inputs;
-               uint32_t out = _plugins[0]->get_info().n_outputs;
+               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);
+                               }
                        }
                }
        }
@@ -404,13 +412,13 @@ PluginInsert::set_parameter (uint32_t port, float val)
 }
 
 void
-PluginInsert::automation_run (vector<Sample *>& bufs, uint32_t nbufs, jack_nframes_t nframes, jack_nframes_t offset)
+PluginInsert::automation_run (vector<Sample *>& bufs, uint32_t nbufs, nframes_t nframes, nframes_t offset)
 {
        ControlEvent next_event (0, 0.0f);
-       jack_nframes_t now = _session.transport_frame ();
-       jack_nframes_t end = now + nframes;
+       nframes_t now = _session.transport_frame ();
+       nframes_t end = now + nframes;
 
-       TentativeLockMonitor lm (_automation_lock, __LINE__, __FILE__);
+       Glib::Mutex::Lock lm (_automation_lock, Glib::TRY_LOCK);
 
        if (!lm.locked()) {
                connect_and_run (bufs, nbufs, nframes, offset, false);
@@ -427,7 +435,7 @@ PluginInsert::automation_run (vector<Sample *>& bufs, uint32_t nbufs, jack_nfram
        
        while (nframes) {
 
-               jack_nframes_t cnt = min (((jack_nframes_t) floor (next_event.when) - now), nframes);
+               nframes_t cnt = min (((nframes_t) ceil (next_event.when) - now), nframes);
   
                connect_and_run (bufs, nbufs, cnt, offset, true, now);
                
@@ -468,7 +476,6 @@ PluginInsert::set_port_automation_state (uint32_t port, AutoState s)
 
                if (s != al.automation_state()) {
                        al.set_automation_state (s);
-                       last_automation_snapshot = 0;
                        _session.set_dirty ();
                }
        }
@@ -497,28 +504,44 @@ PluginInsert::protect_automation ()
 
                switch (al.automation_state()) {
                case Write:
-               case Touch:
                        al.set_automation_state (Off);
                        break;
+               case Touch:
+                       al.set_automation_state (Play);
+                       break;
                default:
                        break;
                }
        }
 }
 
-Plugin*
-PluginInsert::plugin_factory (Plugin& other)
+boost::shared_ptr<Plugin>
+PluginInsert::plugin_factory (boost::shared_ptr<Plugin> other)
 {
-       LadspaPlugin* lp;
+       boost::shared_ptr<LadspaPlugin> lp;
+#ifdef HAVE_SLV2
+       boost::shared_ptr<LV2Plugin> lv2p;
+#endif
 #ifdef VST_SUPPORT
-       VSTPlugin* vp;
+       boost::shared_ptr<VSTPlugin> vp;
+#endif
+#ifdef HAVE_AUDIOUNITS
+       boost::shared_ptr<AUPlugin> ap;
 #endif
 
-       if ((lp = dynamic_cast<LadspaPlugin*> (&other)) != 0) {
-               return new LadspaPlugin (*lp);
+       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 = dynamic_cast<VSTPlugin*> (&other)) != 0) {
-               return new VSTPlugin (*vp);
+       } else if ((vp = boost::dynamic_pointer_cast<VSTPlugin> (other)) != 0) {
+               return boost::shared_ptr<Plugin> (new VSTPlugin (*vp));
+#endif
+#ifdef HAVE_AUDIOUNITS
+       } else if ((ap = boost::dynamic_pointer_cast<AUPlugin> (other)) != 0) {
+               return boost::shared_ptr<Plugin> (new AUPlugin (*ap));
 #endif
        }
 
@@ -526,13 +549,20 @@ PluginInsert::plugin_factory (Plugin& other)
                          X_("unknown plugin type in PluginInsert::plugin_factory"))
              << endmsg;
        /*NOTREACHED*/
-       return 0;
+       return boost::shared_ptr<Plugin> ((Plugin*) 0);
 }
 
 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
@@ -544,8 +574,14 @@ PluginInsert::configure_io (int32_t magic, int32_t in, int32_t out)
 int32_t 
 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;
+       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) {
 
@@ -595,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, 31, "%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();
@@ -614,14 +658,8 @@ PluginInsert::state (bool full)
                XMLNode* child = new XMLNode("port");
                snprintf(buf, sizeof(buf), "%" PRIu32, *x);
                child->add_property("number", string(buf));
-               
-               if (full) {
-                       snprintf(buf, sizeof(buf), "0x%x", automation_list (*x).automation_state ());
-               } else {
-                       snprintf(buf, sizeof(buf), "0x%x", ARDOUR::Off);
-               }
-               child->add_property("auto", string(buf));
-               
+
+               child->add_child_nocopy (automation_list (*x).state (full));
                autonode->add_child_nocopy (*child);
        }
 
@@ -637,8 +675,7 @@ PluginInsert::set_state(const XMLNode& node)
        XMLNodeIterator niter;
        XMLPropertyList plist;
        const XMLProperty *prop;
-       long unique = 0;
-       PluginInfo::Type type;
+       ARDOUR::PluginType type;
 
        if ((prop = node.property ("type")) == 0) {
                error << _("XML node describing insert is missing the `type' field") << endmsg;
@@ -646,9 +683,13 @@ PluginInsert::set_state(const XMLNode& node)
        }
 
        if (prop->value() == X_("ladspa") || prop->value() == X_("Ladspa")) { /* handle old school sessions */
-               type = PluginInfo::LADSPA;
+               type = ARDOUR::LADSPA;
+       } else if (prop->value() == X_("lv2")) {
+               type = ARDOUR::LV2;
        } else if (prop->value() == X_("vst")) {
-               type = PluginInfo::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())
@@ -657,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;
+               }
        }
 
-       Plugin* plugin;
+       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"
@@ -692,19 +738,24 @@ PluginInsert::set_state(const XMLNode& node)
                _plugins.push_back (plugin);
                
                for (uint32_t n=1; n < count; ++n) {
-                       _plugins.push_back (plugin_factory (*plugin));
+                       _plugins.push_back (plugin_factory (plugin));
                }
        }
        
        for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
                if ((*niter)->name() == plugin->state_node_name()) {
-                       for (vector<Plugin*>::iterator i = _plugins.begin(); i != _plugins.end(); ++i) {
+                       for (vector<boost::shared_ptr<Plugin> >::iterator i = _plugins.begin(); i != _plugins.end(); ++i) {
                                (*i)->set_state (**niter);
                        }
                        break;
                }
        } 
 
+       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);
@@ -717,51 +768,89 @@ 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) {
-               if ((*niter)->name() == port_automation_node_name) {
-                       XMLNodeList cnodes;
-                       XMLProperty *cprop;
-                       XMLNodeConstIterator iter;
-                       XMLNode *child;
-                       const char *port;
-                       uint32_t port_id;
-
-                       cnodes = (*niter)->children ("port");
-       
-                       for(iter = cnodes.begin(); iter != cnodes.end(); ++iter){
-                               
-                               child = *iter;
-                               
-                               if ((cprop = child->property("number")) != 0) {
-                                       port = cprop->value().c_str();
-                               } else {
-                                       warning << _("PluginInsert: Auto: no ladspa port number") << endmsg;
-                                       continue;
-                               }
 
-                               sscanf (port, "%" PRIu32, &port_id);
+               if ((*niter)->name() != port_automation_node_name) {
+                       continue;
+               }
 
-                               if (port_id >= _plugins[0]->parameter_count()) {
-                                       warning << _("PluginInsert: Auto: port id out of range") << endmsg;
-                                       continue;
-                               }
-                               
+               XMLNodeList cnodes;
+               XMLProperty *cprop;
+               XMLNodeConstIterator iter;
+               XMLNode *child;
+               const char *port;
+               uint32_t port_id;
+               
+               cnodes = (*niter)->children ("port");
+               
+               for(iter = cnodes.begin(); iter != cnodes.end(); ++iter){
+                       
+                       child = *iter;
+                       
+                       if ((cprop = child->property("number")) != 0) {
+                               port = cprop->value().c_str();
+                       } else {
+                               warning << _("PluginInsert: Auto: no ladspa port number") << endmsg;
+                               continue;
+                       }
+                       
+                       sscanf (port, "%" PRIu32, &port_id);
+                       
+                       if (port_id >= _plugins[0]->parameter_count()) {
+                               warning << _("PluginInsert: Auto: port id out of range") << endmsg;
+                               continue;
+                       }
+
+                       if (!child->children().empty()) {
+                               automation_list (port_id).set_state (*child->children().front());
+                       } else {
                                if ((cprop = child->property("auto")) != 0) {
+                                       
+                                       /* old school */
+
                                        int x;
                                        sscanf (cprop->value().c_str(), "0x%x", &x);
                                        automation_list (port_id).set_automation_state (AutoState (x));
+
+                               } else {
+                                       
+                                       /* missing */
+                                       
+                                       automation_list (port_id).set_automation_state (Off);
                                }
                        }
-                       
-                       break;
+
                }
+
+               /* done */
+
+               break;
        } 
 
        if (niter == nlist.end()) {
@@ -769,7 +858,7 @@ PluginInsert::set_state(const XMLNode& node)
        }
        
        // The name of the PluginInsert comes from the plugin, nothing else
-       set_name(plugin->get_info().name,this);
+       set_name(plugin->get_info()->name,this);
        
        return 0;
 }
@@ -780,51 +869,39 @@ PluginInsert::describe_parameter (uint32_t what)
        return _plugins[0]->describe_parameter (what);
 }
 
-void
-PluginInsert::reset_midi_control (MIDI::Port* port, bool on)
-{
-       _plugins[0]->reset_midi_control (port, on);
-}
-
-void
-PluginInsert::send_all_midi_feedback ()
-{
-       _plugins[0]->send_all_midi_feedback();
-}
-
-jack_nframes_t 
+nframes_t 
 PluginInsert::latency() 
 {
        return _plugins[0]->latency ();
 }
        
-void
-PluginInsert::store_state (PluginInsertState& state) const
-{
-       Redirect::store_state (state);
-       _plugins[0]->store_state (state.plugin_state);
-}
-
-Change
-PluginInsert::restore_state (StateManager::State& state)
-{
-       PluginInsertState* pistate = dynamic_cast<PluginInsertState*> (&state);
-
-       Redirect::restore_state (state);
-
-       _plugins[0]->restore_state (pistate->plugin_state);
-
-       return Change (0);
-}
-
-StateManager::State*
-PluginInsert::state_factory (std::string why) const
+ARDOUR::PluginType
+PluginInsert::type ()
 {
-       PluginInsertState* state = new PluginInsertState (why);
-
-       store_state (*state);
+       boost::shared_ptr<LadspaPlugin> lp;
+#ifdef VST_SUPPORT
+       boost::shared_ptr<VSTPlugin> vp;
+#endif
+#ifdef HAVE_AUDIOUNITS
+       boost::shared_ptr<AUPlugin> ap;
+#endif
+       
+       PluginPtr other = plugin ();
 
-       return state;
+       if ((lp = boost::dynamic_pointer_cast<LadspaPlugin> (other)) != 0) {
+               return ARDOUR::LADSPA;
+#ifdef VST_SUPPORT
+       } else if ((vp = boost::dynamic_pointer_cast<VSTPlugin> (other)) != 0) {
+               return ARDOUR::VST;
+#endif
+#ifdef HAVE_AUDIOUNITS
+       } else if ((ap = boost::dynamic_pointer_cast<AUPlugin> (other)) != 0) {
+               return ARDOUR::AudioUnit;
+#endif
+       } else {
+               /* NOT REACHED */
+               return (ARDOUR::PluginType) 0;
+       }
 }
 
 /***************************************************************
@@ -832,18 +909,17 @@ PluginInsert::state_factory (std::string why) const
  ***************************************************************/
 
 PortInsert::PortInsert (Session& s, Placement p)
-       : Insert (s, p, 1, -1, 1, -1)
+       : Insert (s, string_compose (_("insert %1"), (bitslot = s.next_insert_id()) + 1), p, 1, -1, 1, -1)
 {
        init ();
-       save_state (_("initial state"));
        RedirectCreated (this); /* EMIT SIGNAL */
+
 }
 
 PortInsert::PortInsert (const PortInsert& other)
-       : Insert (other._session, other.placement(), 1, -1, 1, -1)
+       : Insert (other._session, string_compose (_("insert %1"), (bitslot = other._session.next_insert_id()) + 1), other.placement(), 1, -1, 1, -1)
 {
        init ();
-       save_state (_("initial state"));
        RedirectCreated (this); /* EMIT SIGNAL */
 }
 
@@ -864,6 +940,7 @@ PortInsert::init ()
 PortInsert::PortInsert (Session& s, const XMLNode& node)
        : Insert (s, "will change", PreFader)
 {
+       bitslot = 0xffffffff;
        if (set_state (node)) {
                throw failed_constructor();
        }
@@ -873,11 +950,11 @@ PortInsert::PortInsert (Session& s, const XMLNode& node)
 
 PortInsert::~PortInsert ()
 {
-       GoingAway (this);
+       GoingAway ();
 }
 
 void
-PortInsert::run (vector<Sample *>& bufs, uint32_t nbufs, jack_nframes_t nframes, jack_nframes_t offset)
+PortInsert::run (vector<Sample *>& bufs, uint32_t nbufs, nframes_t nframes, nframes_t offset)
 {
        if (n_outputs() == 0) {
                return;
@@ -897,6 +974,7 @@ PortInsert::run (vector<Sample *>& bufs, uint32_t nbufs, jack_nframes_t nframes,
 
        for (o = _outputs.begin(), n = 0; o != _outputs.end(); ++o, ++n) {
                memcpy ((*o)->get_buffer (nframes) + offset, bufs[min(nbufs,n)], sizeof (Sample) * nframes);
+               (*o)->mark_silence (false);
        }
        
        /* collect input */
@@ -916,9 +994,11 @@ XMLNode&
 PortInsert::state (bool full)
 {
        XMLNode *node = new XMLNode("Insert");
-
+       char buf[32];
        node->add_child_nocopy (Redirect::state(full)); 
-       node->add_property("type", "port");
+       node->add_property ("type", "port");
+       snprintf (buf, sizeof (buf), "%" PRIu32, bitslot);
+       node->add_property ("bitslot", buf);
 
        return *node;
 }
@@ -941,6 +1021,17 @@ PortInsert::set_state(const XMLNode& node)
                return -1;
        }
 
+       if ((prop = node.property ("bitslot")) == 0) {
+               bitslot = _session.next_insert_id();
+       } else {
+               uint32_t old_bitslot = bitslot;
+               sscanf (prop->value().c_str(), "%" PRIu32, &bitslot);
+
+               if (old_bitslot != bitslot) {
+                       _session.mark_insert_id (bitslot);
+               }
+       }
+
        for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
                if ((*niter)->name() == Redirect::state_node_name) {
                        Redirect::set_state (**niter);
@@ -956,7 +1047,7 @@ PortInsert::set_state(const XMLNode& node)
        return 0;
 }
 
-jack_nframes_t 
+nframes_t 
 PortInsert::latency() 
 {
        /* because we deliver and collect within the same cycle,
@@ -1043,3 +1134,4 @@ PortInsert::input_streams() const
 {
        return n_outputs ();
 }
+