more solo model work, including a GUI fix for mute button state when the route is...
[ardour.git] / libs / ardour / route.cc
index d4bef141760f8e13dc61dfadd14a8824e73c4543..33af0f8abfc199d0046f3d506ad8ae1c3c4eb735 100644 (file)
@@ -80,7 +80,8 @@ Route::Route (Session& sess, string name, Flag flg, DataType default_type)
         , _meter_point (MeterPostFader)
         , _phase_invert (0)
         , _self_solo (false)
-        , _soloed_by_others (0)
+        , _soloed_by_others_upstream (0)
+        , _soloed_by_others_downstream (0)
         , _solo_isolated (0)
         , _denormal_protection (false)
         , _recordable (true)
@@ -90,7 +91,10 @@ Route::Route (Session& sess, string name, Flag flg, DataType default_type)
        , _mute_control (new MuteControllable (X_("mute"), *this))
        , _mute_master (new MuteMaster (sess, name))
         , _mute_points (MuteMaster::AllPoints)
+        , _path_muted_by_others (false)
         , _have_internal_generator (false)
+        , _physically_connected (false)
+        , _graph_level (-1)
         , _solo_safe (false)
        , _default_type (default_type)
         , _remote_control_id (0)
@@ -124,7 +128,7 @@ Route::init ()
        _amp.reset (new Amp (_session, _mute_master));
        add_processor (_amp, PostFader);
 
-       /* add standard processors other than amp (added by ::init()) */
+       /* add standard processors: meter, main outs, monitor out */
 
        _meter.reset (new PeakMeter (_session));
        _meter->set_display_to_user (false);
@@ -132,7 +136,7 @@ Route::init ()
        add_processor (_meter, PostFader);
 
        _main_outs.reset (new Delivery (_session, _output, _mute_master, _name, Delivery::Main));
-        
+
         add_processor (_main_outs, PostFader);
 
        if (is_monitor()) {
@@ -161,6 +165,10 @@ Route::init ()
                 _main_outs->panner()->set_bypassed (true);
        }
 
+        if (is_master() || is_monitor() || is_hidden()) {
+                _mute_master->set_solo_ignore (true);
+        }
+
        /* now that we have _meter, its safe to connect to this */
 
        Metering::Meter.connect_same_thread (*this, (boost::bind (&Route::meter, this)));
@@ -267,7 +275,7 @@ Route::ensure_track_or_route_name(string name, Session &session)
 {
        string newname = name;
 
-       while (session.route_by_name (newname) != NULL) {
+       while (!session.io_name_is_legal (newname)) {
                newname = bump_name_once (newname);
        }
 
@@ -418,7 +426,7 @@ Route::process_output_buffers (BufferSet& bufs,
                        for (BufferSet::audio_iterator i = bufs.audio_begin(); i != bufs.audio_end(); ++i, ++chn) {
                                Sample* const sp = i->data();
 
-                               if (_phase_invert & chn) {
+                               if (_phase_invert & (1<<chn)) {
                                        for (nframes_t nx = 0; nx < nframes; ++nx) {
                                                sp[nx] = -sp[nx];
                                        }
@@ -447,6 +455,10 @@ Route::process_output_buffers (BufferSet& bufs,
        Glib::RWLock::ReaderLock rm (_processor_lock, Glib::TRY_LOCK);
 
        if (rm.locked()) {
+                //cerr << name() << " upstream solo " << _soloed_by_others_upstream
+                // << " downstream solo " << _soloed_by_others_downstream
+                // << " self " << _self_solo
+                //<< endl;
                for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
 
                        if (bufs.count() != (*i)->input_streams()) {
@@ -520,13 +532,15 @@ Route::passthru_silence (sframes_t start_frame, sframes_t end_frame, nframes_t n
 void
 Route::set_listen (bool yn, void* src)
 {
+        if (_solo_safe) {
+                return;
+        }
+
        if (_monitor_send) {
                if (yn != _monitor_send->active()) {
                        if (yn) {
-                                _monitor_send->set_solo_level (1);
                                _monitor_send->activate ();
                        } else {
-                                _monitor_send->set_solo_level (0);
                                _monitor_send->deactivate ();
                        }
 
@@ -574,8 +588,8 @@ Route::set_solo (bool yn, void *src)
 
        if (self_soloed() != yn) {
                set_self_solo (yn);
-               set_delivery_solo ();
-               solo_changed (src); /* EMIT SIGNAL */
+                set_mute_master_solo ();
+               solo_changed (true, src); /* EMIT SIGNAL */
                _solo_control->Changed (); /* EMIT SIGNAL */
        }
 }
@@ -583,42 +597,67 @@ Route::set_solo (bool yn, void *src)
 void
 Route::set_self_solo (bool yn)
 {
-       _self_solo = yn;
+        _self_solo = yn;
 }
 
 void
-Route::mod_solo_by_others (int32_t delta)
+Route::mod_solo_by_others_upstream (int32_t delta)
 {
+        if (_solo_safe) {
+                return;
+        }
+
        if (delta < 0) {
-               if (_soloed_by_others >= (uint32_t) delta) {
-                       _soloed_by_others += delta;
+               if (_soloed_by_others_upstream >= (uint32_t) abs (delta)) {
+                       _soloed_by_others_upstream += delta;
                } else {
-                       _soloed_by_others = 0;
+                       _soloed_by_others_upstream = 0;
                }
        } else {
-               _soloed_by_others += delta;
+               _soloed_by_others_upstream += delta;
        }
 
-       set_delivery_solo ();
+        set_mute_master_solo ();
+        solo_changed (false, this);
 }
 
 void
-Route::set_delivery_solo ()
+Route::mod_solo_by_others_downstream (int32_t delta)
 {
-       /* tell all delivery processors what the solo situation is, so that they keep
-          delivering even though Session::soloing() is true and they were not
-          explicitly soloed.
-       */
+        if (_solo_safe) {
+                return;
+        }
 
-       Glib::RWLock::ReaderLock rm (_processor_lock);
-       for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
-               boost::shared_ptr<Delivery> d;
-               
-               if ((d = boost::dynamic_pointer_cast<Delivery> (*i)) != 0) {
-                       d->set_solo_level (soloed ());
-                       d->set_solo_isolated (solo_isolated());
+       if (delta < 0) {
+               if (_soloed_by_others_downstream >= (uint32_t) abs (delta)) {
+                       _soloed_by_others_downstream += delta;
+               } else {
+                       _soloed_by_others_downstream = 0;
                }
+       } else {
+               _soloed_by_others_downstream += delta;
        }
+
+        set_mute_master_solo ();
+        solo_changed (false, this);
+}
+
+void
+Route::set_mute_master_solo ()
+{
+        SoloLevel level;
+
+        if (self_soloed()) {
+                level = SelfSoloed;
+        } else if (soloed_by_others_upstream()) {
+                level = UpstreamSoloed;
+        } else if (soloed_by_others_downstream()) {
+                level = DownstreamSoloed;
+        } else {
+                level = NotSoloed;
+        }
+
+        _mute_master->set_solo_level (level);
 }
 
 void
@@ -637,32 +676,32 @@ Route::set_solo_isolated (bool yn, void *src)
 
        boost::shared_ptr<RouteList> routes = _session.get_routes ();
        for (RouteList::iterator i = routes->begin(); i != routes->end(); ++i) {
+
+               if ((*i).get() == this || (*i)->is_master() || (*i)->is_monitor() || (*i)->is_hidden()) {
+                        continue;
+                }
+
                bool sends_only;
-               bool does_feed = feeds (*i, &sends_only);
+               bool does_feed = direct_feeds (*i, &sends_only); // we will recurse anyway, so don't use ::feeds()
                
                if (does_feed && !sends_only) {
                        (*i)->set_solo_isolated (yn, (*i)->route_group());
                }
        }
 
-       bool changed = false;
+        /* XXX should we back-propagate as well? (April 2010: myself and chris goddard think not) */
 
        if (yn) {
-               if (_solo_isolated == 0) {
-                       changed = true;
-               }
                _solo_isolated++;
+                _mute_master->clear_muted_by_others ();
+                solo_isolated_changed (src);
        } else {
-               changed = (_solo_isolated == 1);
                if (_solo_isolated > 0) {
                        _solo_isolated--;
+                        solo_isolated_changed (src);
                }
        }
 
-       if (changed) {
-               set_delivery_solo ();
-               solo_isolated_changed (src);
-       }
 }
 
 bool
@@ -674,13 +713,13 @@ Route::solo_isolated () const
 void
 Route::set_mute_points (MuteMaster::MutePoint mp)
 {
-       _mute_points = mp;
-       mute_points_changed (); /* EMIT SIGNAL */
-
-       if (_mute_master->muted()) {
-               _mute_master->mute_at (_mute_points);
-               mute_changed (this); /* EMIT SIGNAL */
-       }
+        _mute_points = mp;
+        _mute_master->set_mute_points (MuteMaster::AllPoints);
+        mute_points_changed (); /* EMIT SIGNAL */
+        
+        if (_mute_master->muted()) {
+                mute_changed (this); /* EMIT SIGNAL */
+        }
 }
 
 void
@@ -691,21 +730,56 @@ Route::set_mute (bool yn, void *src)
                return;
        }
 
-       if (muted() != yn) {
-               if (yn) {
-                       _mute_master->mute_at (_mute_points);
-               } else {
-                       _mute_master->clear_mute ();
-               }
-
+       if (self_muted() != yn) {
+                _mute_master->set_self_muted (yn);
                mute_changed (src); /* EMIT SIGNAL */
        }
 }
 
 bool
-Route::muted() const
+Route::muted () const
+{
+        return self_muted() || muted_by_others();
+}
+
+bool
+Route::self_muted() const
+{
+       return _mute_master->self_muted ();
+}
+
+bool
+Route::muted_by_others() const
+{
+       return _mute_master->muted_by_others ();
+}
+
+void
+Route::mod_muted_by_others (int delta)
+{
+        if (_solo_isolated) {
+                return;
+        }
+
+        bool old = muted ();
+        _mute_master->mod_muted_by_others (delta);
+        if (old != muted()) {
+                mute_changed (this);
+        }
+}
+
+void
+Route::mod_path_muted_by_others (int32_t delta)
 {
-       return _mute_master->muted ();
+       if (delta < 0) {
+               if (_path_muted_by_others >= (uint32_t) abs (delta)) {
+                       _path_muted_by_others += delta;
+               } else {
+                       _path_muted_by_others = 0;
+               }
+       } else {
+               _path_muted_by_others += delta;
+       }
 }
 
 #if 0
@@ -812,12 +886,6 @@ Route::add_processor (boost::shared_ptr<Processor> processor, ProcessorList::ite
 
                 if (isend && _session.monitor_out() && (isend->target_id() == _session.monitor_out()->id())) {
                         _monitor_send = isend;
-                        
-                        if (_monitor_send->active()) {
-                                _monitor_send->set_solo_level (1);
-                        } else {
-                                _monitor_send->set_solo_level (0);
-                        }
                 }
 
                if (activation_allowed && (processor != _monitor_send)) {
@@ -834,183 +902,6 @@ Route::add_processor (boost::shared_ptr<Processor> processor, ProcessorList::ite
        return 0;
 }
 
-bool
-Route::add_processor_from_xml (const XMLNode& node, ProcessorList::iterator iter)
-{
-       const XMLProperty *prop;
-
-       if (node.name() != "Processor") {
-               return false;
-       }
-
-       try {
-               if ((prop = node.property ("type")) != 0) {
-
-                       boost::shared_ptr<Processor> processor;
-
-                        /* meter, amp, monitor and intreturn are all singletons, deal with them first */
-                        
-                       if (prop->value() == "meter") {
-
-                               if (_meter) {
-                                       if (_meter->set_state (node, Stateful::loading_state_version)) {
-                                               return false;
-                                       } else {
-                                               return true;
-                                       }
-                               }
-
-                                PeakMeter* pm = new PeakMeter (_session);
-
-                                if (pm->set_state (node, Stateful::loading_state_version)) {
-                                        delete pm;
-                                        return false;
-                                }
-
-                               _meter.reset (pm);
-                               _meter->set_display_to_user (_meter_point == MeterCustom);
-
-                               processor = _meter;
-
-                        } else if (prop->value() == "monitor") {
-
-                                if (_monitor_control) {
-                                        if (_monitor_control->set_state (node, Stateful::loading_state_version)) {
-                                                return false;
-                                        } else {
-                                                return true;
-                                        }
-                                }
-
-                                MonitorProcessor* mp = new MonitorProcessor (_session);
-                                if (mp->set_state (node, Stateful::loading_state_version)) {
-                                        delete mp;
-                                        return false;
-                                }
-
-                                _monitor_control.reset (mp);
-                                processor = _monitor_control;
-
-                       } else if (prop->value() == "amp") {
-
-                                if (_amp) {
-                                        processor = _amp;
-                                        if (processor->set_state (node, Stateful::loading_state_version)) {
-                                                return false;
-                                        } else {
-                                                /* no reason to add it */
-                                                return true;
-                                        }
-                                }
-
-                                Amp* a = new Amp (_session, _mute_master);
-                                if (_amp->set_state (node, Stateful::loading_state_version)) {
-                                        delete a;
-                                        return false;
-                                }
-
-                                _amp.reset (a);
-                                processor = _amp;
-
-                       } else if (prop->value() == "intreturn") {
-
-                                /* a route only has one internal return. If it exists already
-                                   just set its state, and return
-                                */
-
-                               if (_intreturn) {
-                                       if (_intreturn->set_state (node, Stateful::loading_state_version)) {
-                                               return false;
-                                       } else {
-                                               return true;
-                                       }
-                               }
-
-                                InternalReturn* iret = new InternalReturn (_session);
-                                if (iret->set_state (node, Stateful::loading_state_version)) { 
-                                        delete iret;
-                                        return false;
-                                }
-
-                               _intreturn.reset (iret);
-                               processor = _intreturn;
-
-                       } else if (prop->value() == "main-outs") {
-
-                               if (_main_outs) {
-                                       if (_main_outs->set_state (node, Stateful::loading_state_version)) {
-                                               return false;
-                                       } else {
-                                               return true;
-                                       }
-                               }
-
-                                Delivery* del = new Delivery (_session, _output, _mute_master, X_("toBeResetFroXML"), Delivery::Role (0));
-                                if (del->set_state (node, Stateful::loading_state_version)) { 
-                                        delete del;
-                                        return false;
-                                }
-
-                               _main_outs.reset (del);
-                               processor = _main_outs;
-
-                       } else if (prop->value() == "intsend") {
-
-                                InternalSend* isend = new InternalSend (_session, _mute_master, boost::shared_ptr<Route>(), Delivery::Role (0));
-                                if (isend->set_state (node, Stateful::loading_state_version)) {
-                                        delete isend;
-                                        return false;
-                                }
-                                
-                                processor.reset (isend);
-
-                        } else if (prop->value() == "ladspa" || prop->value() == "Ladspa" ||
-                                   prop->value() == "lv2" ||
-                                   prop->value() == "vst" ||
-                                   prop->value() == "audiounit") {
-                                
-                               processor.reset (new PluginInsert(_session, node));
-
-                       } else if (prop->value() == "port") {
-
-                               processor.reset (new PortInsert (_session, _mute_master, node));
-
-                       } else if (prop->value() == "send") {
-
-                               processor.reset (new Send (_session, _mute_master, node));
-
-                       } else {
-                               error << string_compose(_("unknown Processor type \"%1\"; ignored"), prop->value()) << endmsg;
-                               return false;
-                       }
-
-                       if (iter == _processors.end() && processor->display_to_user() && !_processors.empty()) {
-                               /* check for invisible processors stacked at the end and leave them there */
-                               ProcessorList::iterator p;
-                               p = _processors.end();
-                               --p;
-                               while (!(*p)->display_to_user() && p != _processors.begin()) {
-                                       --p;
-                               }
-                               ++p;
-                               iter = p;
-                       }
-
-                       return (add_processor (processor, iter, 0, false) == 0);
-
-               } else {
-                       error << _("Processor XML node has no type property") << endmsg;
-                       return false;
-               }
-       }
-
-       catch (failed_constructor &err) {
-               warning << _("processor could not be created. Ignored.") << endmsg;
-               return false;
-       }
-}
-
-
 bool
 Route::add_processor_from_xml_2X (const XMLNode& node, int version, ProcessorList::iterator iter)
 {
@@ -1028,18 +919,18 @@ Route::add_processor_from_xml_2X (const XMLNode& node, int version, ProcessorLis
                                                prop->value() == "vst" ||
                                                prop->value() == "audiounit") {
 
-                                       processor.reset (new PluginInsert (_session, node));
+                                       processor.reset (new PluginInsert (_session));
 
                                } else {
 
-                                       processor.reset (new PortInsert (_session, _mute_master, node));
+                                       processor.reset (new PortInsert (_session, _mute_master));
                                }
 
                        }
 
                } else if (node.name() == "Send") {
 
-                       processor.reset (new Send (_session, _mute_master, node, version));
+                       processor.reset (new Send (_session, _mute_master));
 
                } else {
 
@@ -1047,6 +938,10 @@ Route::add_processor_from_xml_2X (const XMLNode& node, int version, ProcessorLis
                        return false;
                }
 
+                if (processor->set_state (node, version)) {
+                        return false;
+                }
+
                if (iter == _processors.end() && processor->display_to_user() && !_processors.empty()) {
                        /* check for invisible processors stacked at the end and leave them there */
                        ProcessorList::iterator p;
@@ -1608,7 +1503,10 @@ Route::configure_processors_unlocked (ProcessorStreams* err)
 
        /* make sure we have sufficient scratch buffers to cope with the new processor
           configuration */
-       _session.ensure_buffers (n_process_buffers ());
+       {
+               Glib::Mutex::Lock em (_session.engine().process_lock ());
+               _session.ensure_buffers (n_process_buffers ());
+       }
 
        _in_configure_processors = false;
        return 0;
@@ -1769,7 +1667,9 @@ Route::reorder_processors (const ProcessorList& new_order, ProcessorStreams* err
                }
        }
 
-       processors_changed (RouteProcessorChange ()); /* EMIT SIGNAL */
+        if (true) {
+                processors_changed (RouteProcessorChange ()); /* EMIT SIGNAL */
+        }
 
        return 0;
 }
@@ -1830,8 +1730,10 @@ Route::state(bool full_state)
        }
        node->add_property ("order-keys", order_string);
        node->add_property ("self-solo", (_self_solo ? "yes" : "no"));
-       snprintf (buf, sizeof (buf), "%d", _soloed_by_others);
-       node->add_property ("soloed-by-others", buf);
+       snprintf (buf, sizeof (buf), "%d", _soloed_by_others_upstream);
+       node->add_property ("soloed-by-upstream", buf);
+       snprintf (buf, sizeof (buf), "%d", _soloed_by_others_downstream);
+       node->add_property ("soloed-by-downstream", buf);
 
        node->add_child_nocopy (_input->state (full_state));
        node->add_child_nocopy (_output->state (full_state));
@@ -1897,6 +1799,10 @@ Route::_set_state (const XMLNode& node, int version, bool /*call_base*/)
                _flags = Flag (0);
        }
 
+        if (is_master() || is_monitor() || is_hidden()) {
+                _mute_master->set_solo_ignore (true);
+        }
+
        /* add all processors (except amp, which is always present) */
 
        nlist = node.children();
@@ -1929,9 +1835,14 @@ Route::_set_state (const XMLNode& node, int version, bool /*call_base*/)
                set_self_solo (string_is_affirmative (prop->value()));
        }
 
-       if ((prop = node.property ("soloed-by-others")) != 0) {
-               _soloed_by_others = 0; // needed for mod_solo_by_others () to work
-               mod_solo_by_others (atoi (prop->value()));
+       if ((prop = node.property ("soloed-by-upstream")) != 0) {
+               _soloed_by_others_upstream = 0; // needed for mod_.... () to work
+               mod_solo_by_others_upstream (atoi (prop->value()));
+       }
+
+       if ((prop = node.property ("soloed-by-downstream")) != 0) {
+               _soloed_by_others_downstream = 0; // needed for mod_.... () to work
+               mod_solo_by_others_downstream (atoi (prop->value()));
        }
 
        if ((prop = node.property ("solo-isolated")) != 0) {
@@ -1953,7 +1864,8 @@ Route::_set_state (const XMLNode& node, int version, bool /*call_base*/)
        }
 
        if ((prop = node.property (X_("meter-point"))) != 0) {
-               _meter_point = MeterPoint (string_2_enum (prop->value (), _meter_point));
+               MeterPoint mp = MeterPoint (string_2_enum (prop->value (), _meter_point));
+                set_meter_point (mp);
                if (_meter) {
                        _meter->set_display_to_user (_meter_point == MeterCustom);
                }
@@ -2073,7 +1985,7 @@ Route::_set_state_2X (const XMLNode& node, int version)
                bool first = true;
                bool muted = string_is_affirmative (prop->value());
                
-               if(muted){
+               if (muted){
                  
                        string mute_point;
                        
@@ -2123,7 +2035,7 @@ Route::_set_state_2X (const XMLNode& node, int version)
                                }
                        }
                        
-                       _mute_master->set_state (mute_point);
+                       _mute_master->set_mute_points (mute_point);
                }
        }
 
@@ -2316,101 +2228,94 @@ Route::set_processor_state (const XMLNode& node)
 {
        const XMLNodeList &nlist = node.children();
        XMLNodeConstIterator niter;
-       ProcessorList::iterator i, o;
-
-       // Iterate through existing processors, remove those which are not in the state list
+        ProcessorList new_order;
+        bool must_configure = false;
 
-       for (i = _processors.begin(); i != _processors.end(); ) {
-
-               /* leave amp alone, always */
-
-               if ((*i) == _amp) {
-                       ++i;
-                       continue;
-               }
-
-               ProcessorList::iterator tmp = i;
-               ++tmp;
-
-               bool processorInStateList = false;
-
-               for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
-
-                       XMLProperty* id_prop = (*niter)->property(X_("id"));
-
-                       if (id_prop && (*i)->id() == id_prop->value()) {
-                               processorInStateList = true;
-                               break;
-                       }
-               }
-
-               if (!processorInStateList) {
-                       remove_processor (*i);
-               }
-
-               i = tmp;
-       }
-
-       // Iterate through state list and make sure all processors are on the track and in the correct order,
-       // set the state of existing processors according to the new state on the same go
-
-       i = _processors.begin();
-
-       for (niter = nlist.begin(); niter != nlist.end(); ++niter, ++i) {
+       for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
 
                XMLProperty* prop = (*niter)->property ("type");
 
-               o = i;
-
-               // Check whether the next processor in the list is the right one,
-               // except for "amp" which is always there and may not have the
-               // old ID since it is always created anew in every Route
+               if (prop->value() == "amp") {
+                        _amp->set_state (**niter, Stateful::current_state_version);
+                        new_order.push_back (_amp);
+                } else if (prop->value() == "meter") {
+                        _meter->set_state (**niter, Stateful::current_state_version);
+                        new_order.push_back (_meter);
+                } else if (prop->value() == "main-outs") {
+                        _main_outs->set_state (**niter, Stateful::current_state_version);
+                        new_order.push_back (_main_outs);
+                } else if (prop->value() == "intreturn") {
+                        if (!_intreturn) {
+                                _intreturn.reset (new InternalReturn (_session));
+                                must_configure = true;
+                        }
+                        _intreturn->set_state (**niter, Stateful::current_state_version);
+                        new_order.push_back (_intreturn);
+                } else if (is_monitor() && prop->value() == "monitor") {
+                        if (!_monitor_control) {
+                                _monitor_control.reset (new MonitorProcessor (_session));
+                                must_configure = true;
+                        }
+                        _monitor_control->set_state (**niter, Stateful::current_state_version);
+                        new_order.push_back (_monitor_control);
+                } else {
+                        ProcessorList::iterator o;
 
-               if (prop->value() != "amp") {
-                       while (o != _processors.end()) {
+                       for (o = _processors.begin(); o != _processors.end(); ++o) {
                                XMLProperty* id_prop = (*niter)->property(X_("id"));
                                if (id_prop && (*o)->id() == id_prop->value()) {
+                                        (*o)->set_state (**niter, Stateful::current_state_version);
+                                        new_order.push_back (*o);
                                        break;
                                }
-
-                               ++o;
-                       }
-               }
-
-               // If the processor (*niter) is not on the route,
-               // create it and move it to the correct location
-
-               if (o == _processors.end()) {
-
-                       if (add_processor_from_xml (**niter, i)) {
-                               --i; // move iterator to the newly inserted processor
-                       } else {
-                               cerr << "Error restoring route: unable to restore processor" << endl;
                        }
 
-               } else {
-
-                       // Otherwise, the processor already exists; just
-                       // ensure it is at the location provided in the XML state
-
-                       if (i != o) {
-                               boost::shared_ptr<Processor> tmp = (*o);
-                               _processors.erase (o); // remove the old copy
-                               _processors.insert (i, tmp); // insert the processor at the correct location
-                               --i; // move iterator to the correct processor
-                       }
-
-                       // and make it (just) so
+                        // If the processor (*niter) is not on the route then create it 
+                        
+                        if (o == _processors.end()) {
+                                
+                                boost::shared_ptr<Processor> processor;
+
+                                if (prop->value() == "intsend") {
+                                        
+                                        processor.reset (new InternalSend (_session, _mute_master, boost::shared_ptr<Route>(), Delivery::Role (0)));
+                                        
+                                } else if (prop->value() == "ladspa" || prop->value() == "Ladspa" ||
+                                           prop->value() == "lv2" ||
+                                           prop->value() == "vst" ||
+                                           prop->value() == "audiounit") {
+                                        
+                                        processor.reset (new PluginInsert(_session));
+                                        
+                                } else if (prop->value() == "port") {
+                                        
+                                        processor.reset (new PortInsert (_session, _mute_master));
+                                        
+                                } else if (prop->value() == "send") {
+                                        
+                                        processor.reset (new Send (_session, _mute_master));
+                                        
+                                } else {
+                                        error << string_compose(_("unknown Processor type \"%1\"; ignored"), prop->value()) << endmsg;
+                                        continue;
+                                }
 
-                       (*i)->set_state (**niter, Stateful::current_state_version);
-               }
-       }
+                                processor->set_state (**niter, Stateful::current_state_version);
+                                new_order.push_back (processor);
+                                must_configure = true;
+                        }
+                }
+        }
 
-       /* note: there is no configure_processors() call because we figure that
-          the XML state represents a working signal route.
-       */
+        { 
+               Glib::RWLock::WriterLock lm (_processor_lock);
+                _processors = new_order;
+                if (must_configure) {
+                        configure_processors_unlocked (0);
+                }
+        }
 
-       processors_changed (RouteProcessorChange ());
+        processors_changed (RouteProcessorChange ());
 }
 
 void
@@ -2512,11 +2417,6 @@ Route::listen_via (boost::shared_ptr<Route> route, Placement placement, bool /*a
 
                                if (route == _session.monitor_out()) {
                                        _monitor_send = boost::dynamic_pointer_cast<Delivery>(d);
-                                        if (_monitor_send->active()) {
-                                                _monitor_send->set_solo_level (1);
-                                        } else {
-                                                _monitor_send->set_solo_level (0);
-                                        }
                                }
 
                                /* already listening via the specified IO: do nothing */
@@ -2541,8 +2441,6 @@ Route::listen_via (boost::shared_ptr<Route> route, Placement placement, bool /*a
 
                 } else {
                         listener.reset (new InternalSend (_session, _mute_master, route, (aux ? Delivery::Aux : Delivery::Listen)));
-                        if (route == _session.monitor_out()) {
-                        }
                 }
 
        } catch (failed_constructor& err) {
@@ -2607,7 +2505,53 @@ Route::set_comment (string cmt, void *src)
 }
 
 bool
-Route::feeds (boost::shared_ptr<Route> other, bool* only_send)
+Route::add_fed_by (boost::shared_ptr<Route> other, bool via_sends_only)
+{
+        FeedRecord fr (other, via_sends_only);
+
+        pair<FedBy::iterator,bool> result =  _fed_by.insert (fr);
+
+        if (!result.second) {
+
+                /* already a record for "other" - make sure sends-only information is correct */
+                if (!via_sends_only && result.first->sends_only) {
+                        FeedRecord* frp = const_cast<FeedRecord*>(&(*result.first));
+                        frp->sends_only = false;
+                }
+        }
+        
+        return result.second;
+}
+
+void
+Route::clear_fed_by ()
+{
+        _fed_by.clear ();
+}
+
+bool
+Route::feeds (boost::shared_ptr<Route> other, bool* via_sends_only)
+{
+        const FedBy& fed_by (other->fed_by());
+
+        for (FedBy::iterator f = fed_by.begin(); f != fed_by.end(); ++f) {
+                boost::shared_ptr<Route> sr = f->r.lock();
+
+                if (sr && (sr.get() == this)) {
+
+                        if (via_sends_only) {
+                                *via_sends_only = f->sends_only;
+                        }
+
+                        return true;
+                }
+        }
+
+        return false;
+}
+
+bool
+Route::direct_feeds (boost::shared_ptr<Route> other, bool* only_send)
 {
        DEBUG_TRACE (DEBUG::Graph, string_compose ("Feeds? %1\n", _name));
 
@@ -2645,6 +2589,12 @@ Route::feeds (boost::shared_ptr<Route> other, bool* only_send)
        return false;
 }
 
+void
+Route::check_physical_connections ()
+{
+        _physically_connected = _output->physically_connected ();
+}
+
 void
 Route::handle_transport_stopped (bool /*abort_ignored*/, bool did_locate, bool can_flush_processors)
 {
@@ -2856,7 +2806,7 @@ Route::flush_processors ()
 }
 
 void
-Route::set_meter_point (MeterPoint p, void *src)
+Route::set_meter_point (MeterPoint p)
 {
        /* CAN BE CALLED FROM PROCESS CONTEXT */
 
@@ -2918,7 +2868,7 @@ Route::set_meter_point (MeterPoint p, void *src)
        }
 
        _meter_point = p;
-       meter_change (src); /* EMIT SIGNAL */
+       meter_change (); /* EMIT SIGNAL */
 
        bool const meter_visibly_changed = (_meter->display_to_user() != meter_was_visible_to_user);
        
@@ -3104,7 +3054,7 @@ Route::MuteControllable::set_value (float val)
 float
 Route::MuteControllable::get_value (void) const
 {
-       return route.muted() ? 1.0f : 0.0f;
+       return route.self_muted() ? 1.0f : 0.0f;
 }
 
 void
@@ -3257,8 +3207,14 @@ void
 Route::set_phase_invert (bool yn)
 {
        if (_phase_invert != yn) {
-               _phase_invert = 0xffff; // XXX all channels
+                if (yn) {
+                        _phase_invert = 0xffff; // XXX all channels
+                } else {
+                        _phase_invert = 0; // XXX no channels
+                }
+
                phase_invert_changed (); /* EMIT SIGNAL */
+                _session.set_dirty ();
        }
 }
 
@@ -3382,15 +3338,36 @@ Route::nth_send (uint32_t n)
        ProcessorList::iterator i;
 
        for (i = _processors.begin(); i != _processors.end(); ++i) {
-               cerr << "check " << (*i)->name() << endl;
                if (boost::dynamic_pointer_cast<Send> (*i)) {
                        if (n-- == 0) {
                                return *i;
                        }
-               } else {
-                       cerr << "\tnot a send\n";
-               }
+               } 
        }
 
        return boost::shared_ptr<Processor> ();
 }
+
+bool
+Route::has_io_processor_named (const string& name)
+{
+        Glib::RWLock::ReaderLock lm (_processor_lock);
+        ProcessorList::iterator i;
+        
+        for (i = _processors.begin(); i != _processors.end(); ++i) {
+                if (boost::dynamic_pointer_cast<Send> (*i) ||
+                    boost::dynamic_pointer_cast<PortInsert> (*i)) {
+                        if ((*i)->name() == name) {
+                                return true;
+                        }
+                }
+        }
+        
+        return false;
+}
+
+void
+Route::set_graph_level (int32_t l)
+{
+        _graph_level = l;
+}