save/restore VCA master state inside slaves, so that a reloaded session ends up back...
[ardour.git] / libs / ardour / route.cc
index 6209b9f91159a11507e14b31c7dfeee9a1109fcd..411f3dc80178753001bb9dd7d894b800a117bf1c 100644 (file)
@@ -46,6 +46,7 @@
 #include "ardour/capturing_processor.h"
 #include "ardour/debug.h"
 #include "ardour/delivery.h"
+#include "ardour/event_type_map.h"
 #include "ardour/gain_control.h"
 #include "ardour/internal_return.h"
 #include "ardour/internal_send.h"
@@ -74,7 +75,7 @@
 #include "ardour/utils.h"
 #include "ardour/vca.h"
 
-#include "i18n.h"
+#include "pbd/i18n.h"
 
 using namespace std;
 using namespace ARDOUR;
@@ -117,6 +118,11 @@ Route::Route (Session& sess, string name, PresentationInfo::Flag flag, DataType
        processor_max_streams.reset();
 }
 
+boost::weak_ptr<Route>
+Route::weakroute () {
+       return boost::weak_ptr<Route> (shared_from_this ());
+}
+
 int
 Route::init ()
 {
@@ -229,10 +235,6 @@ Route::init ()
                _monitor_control->activate ();
        }
 
-       if (is_master() || is_monitor() || is_auditioner()) {
-               _mute_master->set_solo_ignore (true);
-       }
-
        /* now that we have _meter, its safe to connect to this */
 
        {
@@ -415,6 +417,7 @@ Route::process_output_buffers (BufferSet& bufs,
        bool const meter_already_run = metering_state() == MeteringInput;
 
        framecnt_t latency = 0;
+       const double speed = _session.transport_speed ();
 
        for (ProcessorList::const_iterator i = _processors.begin(); i != _processors.end(); ++i) {
 
@@ -450,7 +453,7 @@ Route::process_output_buffers (BufferSet& bufs,
                                        _initial_delay + latency, longest_session_latency - latency);
                }
 
-               (*i)->run (bufs, start_frame - latency, end_frame - latency, nframes, *i != _processors.back());
+               (*i)->run (bufs, start_frame - latency, end_frame - latency, speed, nframes, *i != _processors.back());
                bufs.set_count ((*i)->output_streams());
 
                if ((*i)->active ()) {
@@ -478,6 +481,7 @@ Route::bounce_process (BufferSet& buffers, framepos_t start, framecnt_t nframes,
        _trim->setup_gain_automation (start, start + nframes, nframes);
 
        latency = 0;
+       const double speed = _session.transport_speed ();
        for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
 
                if (!include_endpoint && (*i) == endpoint) {
@@ -500,7 +504,7 @@ Route::bounce_process (BufferSet& buffers, framepos_t start, framecnt_t nframes,
                 */
                if ((*i) == _main_outs) {
                        assert ((*i)->does_routing());
-                       (*i)->run (buffers, start - latency, start - latency + nframes, nframes, true);
+                       (*i)->run (buffers, start - latency, start - latency + nframes, speed, nframes, true);
                        buffers.set_count ((*i)->output_streams());
                }
 
@@ -508,7 +512,7 @@ Route::bounce_process (BufferSet& buffers, framepos_t start, framecnt_t nframes,
                 * Also don't bother with metering.
                 */
                if (!(*i)->does_routing() && !boost::dynamic_pointer_cast<PeakMeter>(*i)) {
-                       (*i)->run (buffers, start - latency, start - latency + nframes, nframes, true);
+                       (*i)->run (buffers, start - latency, start - latency + nframes, 1.0, nframes, true);
                        buffers.set_count ((*i)->output_streams());
                        latency += (*i)->signal_latency ();
                }
@@ -624,6 +628,9 @@ void
 Route::set_listen (bool yn)
 {
        if (_monitor_send) {
+               if (_monitor_send->active() == yn) {
+                       return;
+               }
                if (yn) {
                        _monitor_send->activate ();
                } else {
@@ -833,6 +840,7 @@ Route::add_processor_from_xml_2X (const XMLNode& node, int version)
                                if (prop->value() == "ladspa" || prop->value() == "Ladspa" ||
                                                prop->value() == "lv2" ||
                                                prop->value() == "windows-vst" ||
+                                               prop->value() == "mac-vst" ||
                                                prop->value() == "lxvst" ||
                                                prop->value() == "audiounit") {
 
@@ -897,6 +905,7 @@ int
 Route::add_processors (const ProcessorList& others, boost::shared_ptr<Processor> before, ProcessorStreams* err)
 {
        ProcessorList::iterator loc;
+       boost::shared_ptr <PluginInsert> fanout;
 
        if (before) {
                loc = find(_processors.begin(), _processors.end(), before);
@@ -955,7 +964,8 @@ Route::add_processors (const ProcessorList& others, boost::shared_ptr<Processor>
 
                if (flags != None) {
                        boost::optional<int> rv = PluginSetup (shared_from_this (), pi, flags);  /* EMIT SIGNAL */
-                       switch (rv.get_value_or (0)) {
+                       int mode = rv.get_value_or (0);
+                       switch (mode & 3) {
                                case 1:
                                        to_skip.push_back (*i); // don't add this one;
                                        break;
@@ -966,6 +976,9 @@ Route::add_processors (const ProcessorList& others, boost::shared_ptr<Processor>
                                default:
                                        break;
                        }
+                       if ((mode & 5) == 4) {
+                               fanout = pi;
+                       }
                }
        }
 
@@ -1016,7 +1029,12 @@ Route::add_processors (const ProcessorList& others, boost::shared_ptr<Processor>
                                }
                        }
 
+                       if (pi && pi->has_sidechain ()) {
+                               pi->sidechain_input ()->changed.connect_same_thread (*this, boost::bind (&Route::sidechain_change_handler, this, _1, _2));
+                       }
+
                        if ((*i)->active()) {
+                               // emit ActiveChanged() and latency_changed() if needed
                                (*i)->activate ();
                        }
 
@@ -1047,6 +1065,11 @@ Route::add_processors (const ProcessorList& others, boost::shared_ptr<Processor>
        processors_changed (RouteProcessorChange ()); /* EMIT SIGNAL */
        set_processor_positions ();
 
+       if (fanout && fanout->configured ()
+                       && fanout->output_streams().n_audio() > 2
+                       && boost::dynamic_pointer_cast<PluginInsert> (the_instrument ()) == fanout) {
+               fan_out (); /* EMIT SIGNAL */
+       }
        return 0;
 }
 
@@ -1075,7 +1098,7 @@ Route::disable_processors (Placement p)
        placement_range(p, start, end);
 
        for (ProcessorList::iterator i = start; i != end; ++i) {
-               (*i)->deactivate ();
+               (*i)->enable (false);
        }
 
        _session.set_dirty ();
@@ -1089,7 +1112,7 @@ Route::disable_processors ()
        Glib::Threads::RWLock::ReaderLock lm (_processor_lock);
 
        for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
-               (*i)->deactivate ();
+               (*i)->enable (false);
        }
 
        _session.set_dirty ();
@@ -1108,7 +1131,7 @@ Route::disable_plugins (Placement p)
 
        for (ProcessorList::iterator i = start; i != end; ++i) {
                if (boost::dynamic_pointer_cast<PluginInsert> (*i)) {
-                       (*i)->deactivate ();
+                       (*i)->enable (false);
                }
        }
 
@@ -1124,7 +1147,7 @@ Route::disable_plugins ()
 
        for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
                if (boost::dynamic_pointer_cast<PluginInsert> (*i)) {
-                       (*i)->deactivate ();
+                       (*i)->enable (false);
                }
        }
 
@@ -1148,8 +1171,8 @@ Route::ab_plugins (bool forward)
                                continue;
                        }
 
-                       if ((*i)->active()) {
-                               (*i)->deactivate ();
+                       if ((*i)->enabled ()) {
+                               (*i)->enable (false);
                                (*i)->set_next_ab_is_active (true);
                        } else {
                                (*i)->set_next_ab_is_active (false);
@@ -1166,11 +1189,7 @@ Route::ab_plugins (bool forward)
                                continue;
                        }
 
-                       if ((*i)->get_next_ab_is_active()) {
-                               (*i)->activate ();
-                       } else {
-                               (*i)->deactivate ();
-                       }
+                       (*i)->enable ((*i)->get_next_ab_is_active ());
                }
        }
 
@@ -1411,7 +1430,7 @@ Route::replace_processor (boost::shared_ptr<Processor> old, boost::shared_ptr<Pr
 
                ProcessorList::iterator i;
                bool replaced = false;
-               bool enable = old->active ();
+               bool enable = old->enabled ();
 
                for (i = _processors.begin(); i != _processors.end(); ) {
                        if (*i == old) {
@@ -1455,7 +1474,7 @@ Route::replace_processor (boost::shared_ptr<Processor> old, boost::shared_ptr<Pr
                }
 
                if (enable) {
-                       sub->activate ();
+                       sub->enable (true);
                }
 
                sub->ActiveChanged.connect_same_thread (*this, boost::bind (&Session::update_latency_compensation, &_session, false));
@@ -1637,8 +1656,9 @@ Route::try_configure_processors_unlocked (ChanCount in, ProcessorStreams* err)
                                 * Delivery::configure_io() will do the actual removal
                                 * by calling _output->ensure_io()
                                 */
-                               if (!is_master() && _session.master_out ()) {
-                                       /* ..but at least as many as there are master-inputs */
+                               if (!is_master() && _session.master_out () && in.n_audio() > 0) {
+                                       /* ..but at least as many as there are master-inputs, if
+                                        * the delivery is dealing with audio */
                                        // XXX this may need special-casing for mixbus (master-outputs)
                                        // and should maybe be a preference anyway ?!
                                        out = ChanCount::max (in, _session.master_out ()->n_inputs ());
@@ -1653,13 +1673,21 @@ Route::try_configure_processors_unlocked (ChanCount in, ProcessorStreams* err)
                        if (is_monitor()) {
                                // restriction for Monitor Section Processors
                                if (in.n_audio() != out.n_audio() || out.n_midi() > 0) {
-                                       /* do not allow to add/remove channels (for now)
-                                        * The Monitor follows the master-bus and has no panner (unpan)
-                                        * but do allow processors with midi-in to be added (e.g VSTs with control that
-                                        * will remain unconnected)
+                                       /* Note: The Monitor follows the master-bus and has no panner.
+                                        *
+                                        * The general idea is to only allow plugins that retain the channel-count
+                                        * and plugins with MIDI in (e.g VSTs with control that will remain unconnected).
+                                        * Then again 5.1 in, monitor stereo is a valid use-case.
+                                        *
+                                        * and worse: we only refuse adding plugins *here*.
+                                        *
+                                        * 1) stereo-master, stereo-mon, add a stereo-plugin, OK
+                                        * 2) change master-bus, add a channel
+                                        * 2a) monitor-secion follows
+                                        * 3) monitor processors fail to re-reconfigure (stereo plugin)
+                                        * 4) re-load session, monitor-processor remains unconfigured, crash.
                                         */
-                                       DEBUG_TRACE (DEBUG::Processors, "Monitor: Channel configuration not allowed.\n");
-                                       return list<pair<ChanCount, ChanCount> > ();
+                                       DEBUG_TRACE (DEBUG::Processors, "Monitor: Channel configuration change.\n");
                                }
                                if (boost::dynamic_pointer_cast<InternalSend> (*p)) {
                                        // internal sends make no sense, only feedback
@@ -1829,12 +1857,7 @@ Route::all_visible_processors_active (bool state)
                if (!(*i)->display_to_user() || boost::dynamic_pointer_cast<Amp> (*i)) {
                        continue;
                }
-
-               if (state) {
-                       (*i)->activate ();
-               } else {
-                       (*i)->deactivate ();
-               }
+               (*i)->enable (state);
        }
 
        _session.set_dirty ();
@@ -1957,6 +1980,35 @@ Route::apply_processor_order (const ProcessorList& new_order)
        maybe_note_meter_position ();
 }
 
+void
+Route::move_instrument_down (bool postfader)
+{
+       Glib::Threads::RWLock::ReaderLock lm (_processor_lock);
+       ProcessorList new_order;
+       boost::shared_ptr<Processor> instrument;
+       for (ProcessorList::const_iterator i = _processors.begin(); i != _processors.end(); ++i) {
+               boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert>(*i);
+               if (pi && pi->plugin ()->get_info ()->is_instrument ()) {
+                       instrument = *i;
+               } else if (instrument && *i == _amp) {
+                       if (postfader) {
+                               new_order.push_back (*i);
+                               new_order.push_back (instrument);
+                       } else {
+                               new_order.push_back (instrument);
+                               new_order.push_back (*i);
+                       }
+               } else {
+                       new_order.push_back (*i);
+               }
+       }
+       if (!instrument) {
+               return;
+       }
+       lm.release ();
+       reorder_processors (new_order, 0);
+}
+
 int
 Route::reorder_processors (const ProcessorList& new_order, ProcessorStreams* err)
 {
@@ -2230,7 +2282,6 @@ Route::state(bool full_state)
 {
        LocaleGuard lg;
        if (!_session._template_state_dir.empty()) {
-               assert (!full_state); // only for templates
                foreach_processor (sigc::bind (sigc::mem_fun (*this, &Route::set_plugin_state_dir), _session._template_state_dir));
        }
 
@@ -2357,10 +2408,6 @@ Route::set_state (const XMLNode& node, int version)
                _strict_io = string_is_affirmative (prop->value());
        }
 
-       if (!can_solo()) {
-               _mute_master->set_solo_ignore (true);
-       }
-
        if (is_monitor()) {
                /* monitor bus does not get a panner, but if (re)created
                   via XML, it will already have one by the time we
@@ -2399,22 +2446,6 @@ Route::set_state (const XMLNode& node, int version)
                        } else {
                                warning << string_compose (_("Pannable state found for route (%1) without a panner!"), name()) << endmsg;
                        }
-               }  else if (child->name() == Controllable::xml_node_name) {
-                       if ((prop = child->property (X_("name"))) == 0) {
-                               continue;
-                       }
-
-                       if (prop->value() == _gain_control->name()) {
-                               _gain_control->set_state (*child, version);
-                       } else if (prop->value() == _solo_control->name()) {
-                               _solo_control->set_state (*child, version);
-                       } else if (prop->value() == _solo_safe_control->name()) {
-                               _solo_safe_control->set_state (*child, version);
-                       } else if (prop->value() == _solo_isolate_control->name()) {
-                               _solo_isolate_control->set_state (*child, version);
-                       } else if (prop->value() == _solo_control->name()) {
-                               _mute_control->set_state (*child, version);
-                       }
                } else if (child->name() == Slavable::xml_node_name) {
                        Slavable::set_state (*child, version);
                }
@@ -2472,13 +2503,32 @@ Route::set_state (const XMLNode& node, int version)
                        XMLNode *cmt = *(child->children().begin());
                        _comment = cmt->content();
 
-               } else if (child->name() == Controllable::xml_node_name && (prop = child->property("name")) != 0) {
-                       if (prop->value() == "solo") {
+               }  else if (child->name() == Controllable::xml_node_name) {
+                       if ((prop = child->property (X_("name"))) == 0) {
+                               continue;
+                       }
+
+                       if (prop->value() == _gain_control->name()) {
+                               _gain_control->set_state (*child, version);
+                       } else if (prop->value() == _solo_control->name()) {
                                _solo_control->set_state (*child, version);
-                       } else if (prop->value() == "mute") {
+                       } else if (prop->value() == _solo_safe_control->name()) {
+                               _solo_safe_control->set_state (*child, version);
+                       } else if (prop->value() == _solo_isolate_control->name()) {
+                               _solo_isolate_control->set_state (*child, version);
+                       } else if (prop->value() == _mute_control->name()) {
                                _mute_control->set_state (*child, version);
+                       } else if (prop->value() == _phase_control->name()) {
+                               _phase_control->set_state (*child, version);
+                       } else {
+                               Evoral::Parameter p = EventTypeMap::instance().from_symbol (prop->value());
+                               if (p.type () >= MidiCCAutomation && p.type () < MidiSystemExclusiveAutomation) {
+                                       boost::shared_ptr<AutomationControl> ac = automation_control (p, true);
+                                       if (ac) {
+                                               ac->set_state (*child, version);
+                                       }
+                               }
                        }
-
                } else if (child->name() == MuteMaster::xml_node_name) {
                        _mute_master->set_state (*child, version);
 
@@ -2512,10 +2562,6 @@ Route::set_state_2X (const XMLNode& node, int version)
 
        Stripable::set_state (node, version);
 
-       if (is_master() || is_monitor() || is_auditioner()) {
-               _mute_master->set_solo_ignore (true);
-       }
-
        if ((prop = node.property (X_("denormal-protection"))) != 0) {
                set_denormal_protection (string_is_affirmative (prop->value()));
        }
@@ -2772,6 +2818,7 @@ Route::set_processor_state (const XMLNode& node)
                                } else if (prop->value() == "ladspa" || prop->value() == "Ladspa" ||
                                           prop->value() == "lv2" ||
                                           prop->value() == "windows-vst" ||
+                                          prop->value() == "mac-vst" ||
                                           prop->value() == "lxvst" ||
                                           prop->value() == "luaproc" ||
                                           prop->value() == "audiounit") {
@@ -2833,6 +2880,7 @@ Route::set_processor_state (const XMLNode& node)
        }
 
        {
+               Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock ());
                Glib::Threads::RWLock::WriterLock lm (_processor_lock);
                /* re-assign _processors w/o process-lock.
                 * if there's an IO-processor present in _processors but
@@ -2840,7 +2888,6 @@ Route::set_processor_state (const XMLNode& node)
                 * a process lock.
                 */
                _processors = new_order;
-               Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock ());
 
                if (must_configure) {
                        configure_processors_unlocked (0, &lm);
@@ -2890,6 +2937,8 @@ Route::silence_unlocked (framecnt_t nframes)
 {
        /* Must be called with the processor lock held */
 
+       const framepos_t now = _session.transport_frame ();
+
        if (!_silent) {
 
                _output->silence (nframes);
@@ -2902,7 +2951,7 @@ Route::silence_unlocked (framecnt_t nframes)
                                continue;
                        }
 
-                       (*i)->silence (nframes);
+                       (*i)->silence (nframes, now);
                }
 
                if (nframes == _session.get_block_size()) {
@@ -2997,8 +3046,7 @@ Route::add_aux_send (boost::shared_ptr<Route> route, boost::shared_ptr<Processor
 
                {
                        Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
-                       boost::shared_ptr<Pannable> sendpan (new Pannable (_session));
-                       listener.reset (new InternalSend (_session, sendpan, _mute_master, boost::dynamic_pointer_cast<ARDOUR::Route>(shared_from_this()), route, Delivery::Aux));
+                       listener.reset (new InternalSend (_session, _pannable, _mute_master, boost::dynamic_pointer_cast<ARDOUR::Route>(shared_from_this()), route, Delivery::Aux));
                }
 
                add_processor (listener, before);
@@ -3176,6 +3224,11 @@ Route::direct_feeds_according_to_reality (boost::shared_ptr<Route> other, bool*
 
                if (iop != 0) {
                        boost::shared_ptr<const IO> iop_out = iop->output();
+                       if (other.get() == this && iop_out && iop->input() && iop_out->connected_to (iop->input())) {
+                               // TODO this needs a delaylines in the Insert to align connections (!)
+                               DEBUG_TRACE (DEBUG::Graph,  string_compose ("\tIOP %1 does feed its own return (%2)\n", iop->name(), other->name()));
+                               continue;
+                       }
                        if ((iop_out && other->all_inputs().fed_by (iop_out)) || iop->feeds (other)) {
                                DEBUG_TRACE (DEBUG::Graph,  string_compose ("\tIOP %1 does feed %2\n", iop->name(), other->name()));
                                if (via_send_only) {
@@ -3394,6 +3447,22 @@ Route::pans_required () const
        return max (n_inputs ().n_audio(), processor_max_streams.n_audio());
 }
 
+void
+Route::flush_processor_buffers_locked (framecnt_t nframes)
+{
+       for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
+               boost::shared_ptr<Delivery> d = boost::dynamic_pointer_cast<Delivery> (*i);
+               if (d) {
+                       d->flush_buffers (nframes);
+               } else {
+                       boost::shared_ptr<PortInsert> p = boost::dynamic_pointer_cast<PortInsert> (*i);
+                       if (p) {
+                               p->flush_buffers (nframes);
+                       }
+               }
+       }
+}
+
 int
 Route::no_roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame, bool session_state_changing)
 {
@@ -3432,13 +3501,15 @@ Route::no_roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame,
        fill_buffers_with_input (bufs, _input, nframes);
 
        if (_meter_point == MeterInput) {
-               _meter->run (bufs, start_frame, end_frame, nframes, true);
+               _meter->run (bufs, start_frame, end_frame, 0.0, nframes, true);
        }
 
        _amp->apply_gain_automation (false);
        _trim->apply_gain_automation (false);
        passthru (bufs, start_frame, end_frame, nframes, 0);
 
+       flush_processor_buffers_locked (nframes);
+
        return 0;
 }
 
@@ -3472,11 +3543,13 @@ Route::roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame, in
        fill_buffers_with_input (bufs, _input, nframes);
 
        if (_meter_point == MeterInput) {
-               _meter->run (bufs, start_frame, end_frame, nframes, true);
+               _meter->run (bufs, start_frame, end_frame, 1.0, nframes, true);
        }
 
        passthru (bufs, start_frame, end_frame, nframes, declick);
 
+       flush_processor_buffers_locked (nframes);
+
        return 0;
 }
 
@@ -3484,6 +3557,7 @@ int
 Route::silent_roll (pframes_t nframes, framepos_t /*start_frame*/, framepos_t /*end_frame*/, bool& /* need_butler */)
 {
        silence (nframes);
+       flush_processor_buffers_locked (nframes);
        return 0;
 }
 
@@ -3707,7 +3781,9 @@ Route::add_export_point()
                Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock ());
                Glib::Threads::RWLock::WriterLock lw (_processor_lock);
 
-               _capturing_processor.reset (new CapturingProcessor (_session));
+               // this aligns all tracks; but not tracks + busses
+               assert (_session.worst_track_latency () >= _initial_delay);
+               _capturing_processor.reset (new CapturingProcessor (_session, _session.worst_track_latency () - _initial_delay));
                _capturing_processor->activate ();
 
                configure_processors_unlocked (0, &lw);
@@ -4485,10 +4561,17 @@ Route::setup_invisible_processors ()
                new_processors.insert (amp, _monitor_control);
        }
 
+       /* TRIM CONTROL */
+
+       if (_trim && _trim->active()) {
+               assert (!_trim->display_to_user ());
+               new_processors.push_front (_trim);
+       }
+
        /* INTERNAL RETURN */
 
-       /* doing this here means that any monitor control will come just after
-          the return.
+       /* doing this here means that any monitor control will come after
+          the return and trim.
        */
 
        if (_intreturn) {
@@ -4496,10 +4579,6 @@ Route::setup_invisible_processors ()
                new_processors.push_front (_intreturn);
        }
 
-       if (_trim && _trim->active()) {
-               assert (!_trim->display_to_user ());
-               new_processors.push_front (_trim);
-       }
        /* EXPORT PROCESSOR */
 
        if (_capturing_processor) {
@@ -4510,8 +4589,8 @@ Route::setup_invisible_processors ()
        _processors = new_processors;
 
        for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
-               if (!(*i)->display_to_user () && !(*i)->active () && (*i) != _monitor_send) {
-                       (*i)->activate ();
+               if (!(*i)->display_to_user () && !(*i)->enabled () && (*i) != _monitor_send) {
+                       (*i)->enable (true);
                }
        }
 
@@ -5239,17 +5318,11 @@ Route::muted_by_others_soloing () const
                return false;
        }
 
-       return _session.soloing() && !_solo_control->soloed() && !_solo_isolate_control->solo_isolated();
+       return  _session.soloing() && !_solo_control->soloed() && !_solo_isolate_control->solo_isolated();
 }
 
 void
 Route::clear_all_solo_state ()
 {
-       double v = _solo_safe_control->get_value ();
-
        _solo_control->clear_all_solo_state ();
-
-       if (v != 0.0) {
-               _solo_safe_control->set_value (v, Controllable::NoGroup);
-       }
 }