Remove muting behaviour from the Amp processor. Fix some small
[ardour.git] / libs / ardour / route.cc
index 239a189a0d205e1147c3a09bcf7aa2782c03604a..c0edb1a996c4b40234be723f62eba1758fb3f97b 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)
@@ -89,7 +90,6 @@ Route::Route (Session& sess, string name, Flag flg, DataType default_type)
        , _solo_control (new SoloControllable (X_("solo"), *this))
        , _mute_control (new MuteControllable (X_("mute"), *this))
        , _mute_master (new MuteMaster (sess, name))
-        , _mute_points (MuteMaster::AllPoints)
         , _have_internal_generator (false)
         , _solo_safe (false)
        , _default_type (default_type)
@@ -121,7 +121,7 @@ Route::init ()
 
        /* add amp processor  */
 
-       _amp.reset (new Amp (_session, _mute_master));
+       _amp.reset (new Amp (_session));
        add_processor (_amp, PostFader);
 
        /* add standard processors: meter, main outs, monitor out */
@@ -161,7 +161,9 @@ Route::init ()
                 _main_outs->panner()->set_bypassed (true);
        }
 
-        markup_solo_ignore ();
+        if (is_master() || is_monitor() || is_hidden()) {
+                _mute_master->set_solo_ignore (true);
+        }
 
        /* now that we have _meter, its safe to connect to this */
 
@@ -449,6 +451,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()) {
@@ -529,11 +535,11 @@ Route::set_listen (bool yn, void* src)
        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);
+                                _mute_master->set_soloed (true);
+                        } else {
                                _monitor_send->deactivate ();
+                                _mute_master->set_soloed (false);
                        }
 
                        listen_changed (src); /* EMIT SIGNAL */
@@ -580,7 +586,7 @@ Route::set_solo (bool yn, void *src)
 
        if (self_soloed() != yn) {
                set_self_solo (yn);
-               set_delivery_solo ();
+                set_mute_master_solo ();
                solo_changed (true, src); /* EMIT SIGNAL */
                _solo_control->Changed (); /* EMIT SIGNAL */
        }
@@ -593,43 +599,87 @@ Route::set_self_solo (bool yn)
 }
 
 void
-Route::mod_solo_by_others (int32_t delta)
+Route::mod_solo_by_others_upstream (int32_t delta)
 {
         if (_solo_safe) {
                 return;
         }
 
+        uint32_t old_sbu = _soloed_by_others_upstream;
+
        if (delta < 0) {
-               if (_soloed_by_others >= (uint32_t) abs (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;
+       }
+
+        DEBUG_TRACE (DEBUG::Solo, string_compose ("%1 SbU delta %2 = %3 old = %4 sbd %5 ss %6 exclusive %7\n",
+                                                  name(), delta, _soloed_by_others_upstream, old_sbu, 
+                                                  _soloed_by_others_downstream, _self_solo, Config->get_exclusive_solo()));
+
+        /* push the inverse solo change to everything that feeds us. 
+           
+           This is important for solo-within-group. When we solo 1 track out of N that
+           feed a bus, that track will cause mod_solo_by_upstream (+1) to be called
+           on the bus. The bus then needs to call mod_solo_by_downstream (-1) on all
+           tracks that feed it. This will silence them if they were audible because
+           of a bus solo, but the newly soloed track will still be audible (because 
+           it is self-soloed).
+           
+           but .. do this only when we are being told to solo-by-upstream (i.e delta = +1),
+           not in reverse.
+         */
+
+        if ((_self_solo || _soloed_by_others_downstream) &&
+            ((old_sbu == 0 && _soloed_by_others_upstream > 0) || 
+             (old_sbu > 0 && _soloed_by_others_upstream == 0))) {
+                
+                if (delta > 0 || !Config->get_exclusive_solo()) {
+                        DEBUG_TRACE (DEBUG::Solo, "\t ... INVERT push\n");
+                        for (FedBy::iterator i = _fed_by.begin(); i != _fed_by.end(); ++i) {
+                                boost::shared_ptr<Route> sr = i->r.lock();
+                                if (sr) {
+                                        sr->mod_solo_by_others_downstream (-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;
        }
+
+        DEBUG_TRACE (DEBUG::Solo, string_compose ("%1 SbD delta %2 = %3\n", name(), delta, _soloed_by_others_downstream));
+
+        set_mute_master_solo ();
+        solo_changed (false, this);
+}
+
+void
+Route::set_mute_master_solo ()
+{
+        _mute_master->set_soloed (self_soloed() || soloed_by_others_downstream() || soloed_by_others_upstream());
 }
 
 void
@@ -648,34 +698,42 @@ 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 = direct_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());
                }
        }
 
-        /* XXX should we back-propagate as well? */
+        /* XXX should we back-propagate as well? (April 2010: myself and chris goddard think not) */
 
-       bool changed = false;
+        bool changed = false;
 
        if (yn) {
-               if (_solo_isolated == 0) {
-                       changed = true;
-               }
+                if (_solo_isolated == 0) {
+                        _mute_master->set_solo_ignore (true);
+                        changed = true;
+                }
                _solo_isolated++;
        } else {
-               changed = (_solo_isolated == 1);
                if (_solo_isolated > 0) {
                        _solo_isolated--;
+                        if (_solo_isolated == 0) {
+                                _mute_master->set_solo_ignore (false);
+                                changed = true;
+                        }
                }
        }
 
-       if (changed) {
-               set_delivery_solo ();
-               solo_isolated_changed (src);
-       }
+        if (changed) {
+                solo_isolated_changed (src);
+        }
 }
 
 bool
@@ -687,14 +745,11 @@ Route::solo_isolated () const
 void
 Route::set_mute_points (MuteMaster::MutePoint mp)
 {
-        if (mp != _mute_points) {
-                _mute_points = mp;
-                _mute_master->set_mute_points (_mute_points);
-                mute_points_changed (); /* EMIT SIGNAL */
-
-                if (_mute_master->muted()) {
-                        mute_changed (this); /* EMIT SIGNAL */
-                }
+        _mute_master->set_mute_points (mp);
+        mute_points_changed (); /* EMIT SIGNAL */
+        
+        if (_mute_master->muted()) {
+                mute_changed (this); /* EMIT SIGNAL */
         }
 }
 
@@ -706,8 +761,8 @@ Route::set_mute (bool yn, void *src)
                return;
        }
 
-       if (self_muted() != yn) {
-                _mute_master->set_self_muted (yn);
+       if (muted() != yn) {
+                _mute_master->set_muted (yn);
                mute_changed (src); /* EMIT SIGNAL */
        }
 }
@@ -715,31 +770,7 @@ Route::set_mute (bool yn, void *src)
 bool
 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)
-{
-        bool old = muted ();
-
-        _mute_master->mod_muted_by_others (delta);
-
-        if (old != muted()) {
-                mute_changed (this);
-        }
+        return _mute_master->muted();
 }
 
 #if 0
@@ -846,12 +877,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)) {
@@ -864,6 +889,7 @@ Route::add_processor (boost::shared_ptr<Processor> processor, ProcessorList::ite
        }
 
        processors_changed (RouteProcessorChange ()); /* EMIT SIGNAL */
+       set_processor_positions ();
 
        return 0;
 }
@@ -1008,6 +1034,7 @@ Route::add_processors (const ProcessorList& others, ProcessorList::iterator iter
        }
 
        processors_changed (RouteProcessorChange ()); /* EMIT SIGNAL */
+       set_processor_positions ();
 
        return 0;
 }
@@ -1208,6 +1235,7 @@ Route::clear_processors (Placement p)
        processor_max_streams.reset();
        _have_internal_generator = false;
        processors_changed (RouteProcessorChange ()); /* EMIT SIGNAL */
+       set_processor_positions ();
 
        if (!already_deleting) {
                _session.clear_deletion_in_progress();
@@ -1299,6 +1327,7 @@ Route::remove_processor (boost::shared_ptr<Processor> processor, ProcessorStream
 
        processor->drop_references ();
        processors_changed (RouteProcessorChange ()); /* EMIT SIGNAL */
+       set_processor_positions ();
 
        return 0;
 }
@@ -1390,6 +1419,7 @@ Route::remove_processors (const ProcessorList& to_be_deleted, ProcessorStreams*
        }
 
        processors_changed (RouteProcessorChange ()); /* EMIT SIGNAL */
+       set_processor_positions ();
 
        return 0;
 }
@@ -1635,6 +1665,7 @@ Route::reorder_processors (const ProcessorList& new_order, ProcessorStreams* err
 
         if (true) {
                 processors_changed (RouteProcessorChange ()); /* EMIT SIGNAL */
+               set_processor_positions ();
         }
 
        return 0;
@@ -1696,8 +1727,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));
@@ -1763,6 +1796,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();
@@ -1795,9 +1832,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) {
@@ -1940,7 +1982,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;
                        
@@ -2270,28 +2312,8 @@ Route::set_processor_state (const XMLNode& node)
                 }
         }
 
-        markup_solo_ignore ();
-
         processors_changed (RouteProcessorChange ());
-}
-
-void
-Route::markup_solo_ignore ()
-{
-        Glib::RWLock::ReaderLock lm (_processor_lock);
-        
-        for (ProcessorList::iterator p = _processors.begin(); p !=  _processors.end(); ++p) {
-
-                /* all delivery processors on master, monitor and auditioner never ever pay attention to solo
-                 */
-
-                boost::shared_ptr<Delivery> d = boost::dynamic_pointer_cast<Delivery>(*p);
-                
-                if (d && (is_master() || is_monitor() || is_hidden())) {
-                        cerr << _name << " Found a delivery unit, mark solo ignored\n";
-                        d->set_solo_ignored (true);
-                }
-        }
+       set_processor_positions ();
 }
 
 void
@@ -2393,11 +2415,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 */
@@ -3340,3 +3357,23 @@ Route::has_io_processor_named (const string& name)
         
         return false;
 }
+
+MuteMaster::MutePoint
+Route::mute_points () const
+{
+       return _mute_master->mute_points ();
+}
+
+void
+Route::set_processor_positions ()
+{
+       Glib::RWLock::ReaderLock lm (_processor_lock);
+
+       bool had_amp = false;
+       for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
+               (*i)->set_pre_fader (!had_amp);
+               if (boost::dynamic_pointer_cast<Amp> (*i)) {
+                       had_amp = true;
+               }
+       }
+}