merge fix
[ardour.git] / libs / ardour / route.cc
index 5df1be71cb6b634b715b2ae9ff17a15d09479538..34d92b7a7e30605d5ae9def5288614c32bd615ee 100644 (file)
@@ -60,6 +60,7 @@
 #include "ardour/port.h"
 #include "ardour/port_insert.h"
 #include "ardour/processor.h"
+#include "ardour/profile.h"
 #include "ardour/route.h"
 #include "ardour/route_group.h"
 #include "ardour/send.h"
@@ -96,6 +97,7 @@ Route::Route (Session& sess, string name, Flag flg, DataType default_type)
        , _soloed_by_others_upstream (0)
        , _soloed_by_others_downstream (0)
        , _solo_isolated (0)
+       , _solo_isolated_by_upstream (0)
        , _denormal_protection (false)
        , _recordable (true)
        , _silent (false)
@@ -111,17 +113,23 @@ Route::Route (Session& sess, string name, Flag flg, DataType default_type)
        , _in_configure_processors (false)
        , _initial_io_setup (false)
        , _custom_meter_position_noted (false)
-       , _last_custom_meter_was_at_end (false)
 {
-       if (is_master()) {
-               _meter_type = MeterK20;
-       }
        processor_max_streams.reset();
 }
 
 int
 Route::init ()
 {
+       /* set default meter type */
+       if (is_master()) {
+               _meter_type = Config->get_meter_type_master ();
+       }
+       else if (dynamic_cast<Track*>(this)) {
+               _meter_type = Config->get_meter_type_track ();
+       } else {
+               _meter_type = Config->get_meter_type_bus ();
+       }
+
        /* add standard controls */
 
        _solo_control.reset (new SoloControllable (X_("solo"), shared_from_this ()));
@@ -207,8 +215,6 @@ Route::init ()
 
        /* now that we have _meter, its safe to connect to this */
 
-       Metering::Meter.connect_same_thread (*this, (boost::bind (&Route::meter, this)));
-
        {
                Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock ());
                configure_processors (0);
@@ -570,7 +576,7 @@ Route::process_output_buffers (BufferSet& bufs,
 
        framecnt_t latency = 0;
 
-       for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
+       for (ProcessorList::const_iterator i = _processors.begin(); i != _processors.end(); ++i) {
 
                if (meter_already_run && boost::dynamic_pointer_cast<PeakMeter> (*i)) {
                        /* don't ::run() the meter, otherwise it will have its previous peak corrupted */
@@ -836,6 +842,14 @@ Route::set_solo (bool yn, void *src)
                solo_changed (true, src); /* EMIT SIGNAL */
                _solo_control->Changed (); /* EMIT SIGNAL */
        }
+
+       /* XXX TRACKS DEVELOPERS: THIS LOGIC SUGGESTS THAT YOU ARE NOT AWARE OF
+          Config->get_solo_mute_overrride().
+       */
+
+       if (yn && Profile->get_trx()) {
+               set_mute (false, src);
+       }
 }
 
 void
@@ -938,6 +952,28 @@ Route::set_mute_master_solo ()
        _mute_master->set_soloed (self_soloed() || soloed_by_others_downstream() || soloed_by_others_upstream());
 }
 
+void
+Route::mod_solo_isolated_by_upstream (bool yn, void* src)
+{
+       bool old = solo_isolated ();
+
+       if (!yn) {
+               if (_solo_isolated_by_upstream >= 1) {
+                       _solo_isolated_by_upstream--;
+               } else {
+                       _solo_isolated_by_upstream = 0;
+               }
+       } else {
+               _solo_isolated_by_upstream++;
+       }
+
+       if (solo_isolated() != old) {
+               /* solo isolated status changed */
+               _mute_master->set_solo_ignore (yn);
+               solo_isolated_changed (src);
+       }
+}
+
 void
 Route::set_solo_isolated (bool yn, void *src)
 {
@@ -950,25 +986,6 @@ Route::set_solo_isolated (bool yn, void *src)
                return;
        }
 
-       /* forward propagate solo-isolate status to everything fed by this route, but not those via sends only */
-
-       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_auditioner()) {
-                       continue;
-               }
-
-               bool sends_only;
-               bool does_feed = direct_feeds_according_to_graph (*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? (April 2010: myself and chris goddard think not) */
-
        bool changed = false;
 
        if (yn) {
@@ -987,15 +1004,37 @@ Route::set_solo_isolated (bool yn, void *src)
                }
        }
 
-       if (changed) {
-               solo_isolated_changed (src);
+       
+       if (!changed) {
+               return;
+       }
+       
+       /* forward propagate solo-isolate status to everything fed by this route, but not those via sends only */
+
+       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_auditioner()) {
+                       continue;
+               }
+               
+               bool sends_only;
+               bool does_feed = feeds (*i, &sends_only);
+               
+               if (does_feed && !sends_only) {
+                       (*i)->mod_solo_isolated_by_upstream (yn, src);
+               }
        }
+       
+       /* XXX should we back-propagate as well? (April 2010: myself and chris goddard think not) */
+
+       solo_isolated_changed (src);
 }
 
 bool
 Route::solo_isolated () const
 {
-       return _solo_isolated > 0;
+       return (_solo_isolated > 0) || (_solo_isolated_by_upstream > 0);
 }
 
 void
@@ -1036,6 +1075,17 @@ Route::muted () const
        return _mute_master->muted_by_self();
 }
 
+bool
+Route::muted_by_others () const
+{
+       //master is never muted by others
+       if (is_master())
+               return false;
+               
+       //now check to see if something is soloed (and I am not)
+       return (_session.soloing() && !self_soloed() && !solo_isolated());
+}
+
 #if 0
 static void
 dump_processors(const string& name, const list<boost::shared_ptr<Processor> >& procs)
@@ -1191,7 +1241,7 @@ Route::add_processor (boost::shared_ptr<Processor> processor, boost::shared_ptr<
 
                }
 
-               if (activation_allowed && !_session.get_disable_all_loaded_plugins()) {
+               if (activation_allowed && (!_session.get_disable_all_loaded_plugins () || !processor->display_to_user ())) {
                        processor->activate ();
                }
 
@@ -1271,7 +1321,7 @@ Route::add_processor_from_xml_2X (const XMLNode& node, int version)
                //A2 uses the "active" flag in the toplevel redirect node, not in the child plugin/IO
                if (i != children.end()) {
                        if ((prop = (*i)->property (X_("active"))) != 0) {
-                               if ( string_is_affirmative (prop->value()) && !_session.get_disable_all_loaded_plugins() )
+                               if ( string_is_affirmative (prop->value()) && (!_session.get_disable_all_loaded_plugins () || !processor->display_to_user () ) )
                                        processor->activate();
                                else
                                        processor->deactivate();
@@ -1899,6 +1949,14 @@ Route::configure_processors_unlocked (ProcessorStreams* err)
                (*p)->configure_io(c->first, c->second);
                processor_max_streams = ChanCount::max(processor_max_streams, c->first);
                processor_max_streams = ChanCount::max(processor_max_streams, c->second);
+
+               boost::shared_ptr<PluginInsert> pi;
+               if ((pi = boost::dynamic_pointer_cast<PluginInsert>(*p)) != 0) {
+                       /* plugins connected via Split Match may have more channels.
+                        * route/scratch buffers are needed for all of them*/
+                       processor_max_streams = ChanCount::max(processor_max_streams, pi->input_streams());
+                       processor_max_streams = ChanCount::max(processor_max_streams, pi->natural_input_streams());
+               }
                out = c->second;
 
                if (boost::dynamic_pointer_cast<Delivery> (*p)
@@ -1916,7 +1974,7 @@ Route::configure_processors_unlocked (ProcessorStreams* err)
 
 
        if (_meter) {
-               _meter->reset_max_channels (processor_max_streams);
+               _meter->set_max_channels (processor_max_streams);
        }
 
        /* make sure we have sufficient scratch buffers to cope with the new processor
@@ -2237,8 +2295,6 @@ Route::state(bool full_state)
                        after->id().print (buf, sizeof (buf));
                        node->add_property (X_("processor-after-last-custom-meter"), buf);
                }
-
-               node->add_property (X_("last-custom-meter-was-at-end"), _last_custom_meter_was_at_end ? "yes" : "no");
        }
 
        return *node;
@@ -2431,10 +2487,6 @@ Route::set_state (const XMLNode& node, int version)
                }
        }
 
-       if ((prop = node.property (X_("last-custom-meter-was-at-end"))) != 0) {
-               _last_custom_meter_was_at_end = string_is_affirmative (prop->value ());
-       }
-
        for (niter = nlist.begin(); niter != nlist.end(); ++niter){
                child = *niter;
 
@@ -3382,15 +3434,21 @@ Route::flush_processors ()
 #ifdef __clang__
 __attribute__((annotate("realtime")))
 #endif
-void
+bool
 Route::apply_processor_changes_rt ()
 {
+       int emissions = EmitNone;
+
        if (_pending_meter_point != _meter_point) {
                Glib::Threads::RWLock::WriterLock pwl (_processor_lock, Glib::Threads::TRY_LOCK);
                if (pwl.locked()) {
                        /* meters always have buffers for 'processor_max_streams'
                         * they can be re-positioned without re-allocation */
-                       set_meter_point_unlocked();
+                       if (set_meter_point_unlocked()) {
+                               emissions |= EmitMeterChanged | EmitMeterVisibilityChange;;
+                       } else {
+                               emissions |= EmitMeterChanged;
+                       }
                }
        }
 
@@ -3401,15 +3459,38 @@ Route::apply_processor_changes_rt ()
                if (pwl.locked()) {
                        apply_processor_order (_pending_processor_order);
                        setup_invisible_processors ();
-
                        changed = true;
                        g_atomic_int_set (&_pending_process_reorder, 0);
+                       emissions |= EmitRtProcessorChange;
                }
        }
        if (changed) {
-               processors_changed (RouteProcessorChange (RouteProcessorChange::RealTimeChange)); /* EMIT SIGNAL */
                set_processor_positions ();
        }
+       if (emissions != 0) {
+               g_atomic_int_set (&_pending_signals, emissions);
+               return true;
+       }
+       return false;
+}
+
+void
+Route::emit_pending_signals ()
+{
+
+       int sig = g_atomic_int_and (&_pending_signals, 0);
+       if (sig & EmitMeterChanged) {
+               _meter->emit_configuration_changed();
+               meter_change (); /* EMIT SIGNAL */
+               if (sig & EmitMeterVisibilityChange) {
+               processors_changed (RouteProcessorChange (RouteProcessorChange::MeterPointChange, true)); /* EMIT SIGNAL */
+               } else {
+               processors_changed (RouteProcessorChange (RouteProcessorChange::MeterPointChange, false)); /* EMIT SIGNAL */
+               }
+       }
+       if (sig & EmitRtProcessorChange) {
+               processors_changed (RouteProcessorChange (RouteProcessorChange::RealTimeChange)); /* EMIT SIGNAL */
+       }
 }
 
 void
@@ -3423,7 +3504,13 @@ Route::set_meter_point (MeterPoint p, bool force)
                Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock ());
                Glib::Threads::RWLock::WriterLock lm (_processor_lock);
                _pending_meter_point = p;
-               set_meter_point_unlocked();
+               _meter->emit_configuration_changed();
+               meter_change (); /* EMIT SIGNAL */
+               if (set_meter_point_unlocked()) {
+                       processors_changed (RouteProcessorChange (RouteProcessorChange::MeterPointChange, true)); /* EMIT SIGNAL */
+               } else {
+                       processors_changed (RouteProcessorChange (RouteProcessorChange::MeterPointChange, false)); /* EMIT SIGNAL */
+               }
        } else {
                _pending_meter_point = p;
        }
@@ -3433,7 +3520,7 @@ Route::set_meter_point (MeterPoint p, bool force)
 #ifdef __clang__
 __attribute__((annotate("realtime")))
 #endif
-void
+bool
 Route::set_meter_point_unlocked ()
 {
 #ifndef NDEBUG
@@ -3447,7 +3534,9 @@ Route::set_meter_point_unlocked ()
 
        bool meter_was_visible_to_user = _meter->display_to_user ();
 
-       maybe_note_meter_position ();
+       if (!_custom_meter_position_noted) {
+               maybe_note_meter_position ();
+       }
 
        if (_meter_point != MeterCustom) {
 
@@ -3456,23 +3545,20 @@ Route::set_meter_point_unlocked ()
                setup_invisible_processors ();
 
        } else {
-
                _meter->set_display_to_user (true);
 
                /* If we have a previous position for the custom meter, try to put it there */
-               if (_custom_meter_position_noted) {
-                       boost::shared_ptr<Processor> after = _processor_after_last_custom_meter.lock ();
-                       
-                       if (after) {
-                               ProcessorList::iterator i = find (_processors.begin(), _processors.end(), after);
-                               if (i != _processors.end ()) {
-                                       _processors.remove (_meter);
-                                       _processors.insert (i, _meter);
-                               }
-                       } else if (_last_custom_meter_was_at_end) {
+               boost::shared_ptr<Processor> after = _processor_after_last_custom_meter.lock ();
+               if (after) {
+                       ProcessorList::iterator i = find (_processors.begin(), _processors.end(), after);
+                       if (i != _processors.end ()) {
                                _processors.remove (_meter);
-                               _processors.push_back (_meter);
+                               _processors.insert (i, _meter);
                        }
+               } else {// at end, right before the mains_out/panner
+                       _processors.remove (_meter);
+                       ProcessorList::iterator main = _processors.end();
+                       _processors.insert (--main, _meter);
                }
        }
 
@@ -3502,9 +3588,7 @@ Route::set_meter_point_unlocked ()
         * but all those signals are subscribed to with gui_thread()
         * so we're safe.
         */
-       meter_change (); /* EMIT SIGNAL */
-       bool const meter_visibly_changed = (_meter->display_to_user() != meter_was_visible_to_user);
-       processors_changed (RouteProcessorChange (RouteProcessorChange::MeterPointChange, meter_visibly_changed)); /* EMIT SIGNAL */
+        return (_meter->display_to_user() != meter_was_visible_to_user);
 }
 
 void
@@ -3996,28 +4080,6 @@ Route::set_active (bool yn, void* src)
        }
 }
 
-void
-Route::meter ()
-{
-       Glib::Threads::RWLock::ReaderLock rm (_processor_lock);
-
-       assert (_meter);
-
-       _meter->meter ();
-
-       for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
-
-               boost::shared_ptr<Send> s;
-               boost::shared_ptr<Return> r;
-
-               if ((s = boost::dynamic_pointer_cast<Send> (*i)) != 0) {
-                       s->meter()->meter();
-               } else if ((r = boost::dynamic_pointer_cast<Return> (*i)) != 0) {
-                       r->meter()->meter ();
-               }
-       }
-}
-
 boost::shared_ptr<Pannable>
 Route::pannable() const
 {
@@ -4137,9 +4199,9 @@ Route::set_processor_positions ()
        Glib::Threads::RWLock::ReaderLock lm (_processor_lock);
 
        bool had_amp = false;
-       for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
+       for (ProcessorList::const_iterator i = _processors.begin(); i != _processors.end(); ++i) {
                (*i)->set_pre_fader (!had_amp);
-               if (boost::dynamic_pointer_cast<Amp> (*i)) {
+               if (*i == _amp) {
                        had_amp = true;
                }
        }
@@ -4334,7 +4396,7 @@ Route::setup_invisible_processors ()
        /* find the amp */
 
        ProcessorList::iterator amp = new_processors.begin ();
-       while (amp != new_processors.end() && boost::dynamic_pointer_cast<Amp> (*amp) == 0) {
+       while (amp != new_processors.end() && *amp != _amp) {
                ++amp;
        }
 
@@ -4467,6 +4529,12 @@ 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)->activate ();
+               }
+       }
+
        DEBUG_TRACE (DEBUG::Processors, string_compose ("%1: setup_invisible_processors\n", _name));
        for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
                DEBUG_TRACE (DEBUG::Processors, string_compose ("\t%1\n", (*i)->name ()));
@@ -4504,18 +4572,32 @@ Route::maybe_note_meter_position ()
        }
        
        _custom_meter_position_noted = true;
+       /* custom meter points range from after trim to before panner/main_outs
+        * this is a limitation by the current processor UI
+        */
+       bool seen_trim = false;
+       _processor_after_last_custom_meter.reset();
        for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
+               if ((*i) == _trim) {
+                       seen_trim = true;
+               }
+               if ((*i) == _main_outs) {
+                       _processor_after_last_custom_meter = *i;
+                       break;
+               }
                if (boost::dynamic_pointer_cast<PeakMeter> (*i)) {
-                       ProcessorList::iterator j = i;
-                       ++j;
-                       if (j != _processors.end ()) {
-                               _processor_after_last_custom_meter = *j;
-                               _last_custom_meter_was_at_end = false;
+                       if (!seen_trim) {
+                               _processor_after_last_custom_meter = _trim;
                        } else {
-                               _last_custom_meter_was_at_end = true;
+                               ProcessorList::iterator j = i;
+                               ++j;
+                               assert(j != _processors.end ()); // main_outs should be before
+                               _processor_after_last_custom_meter = *j;
                        }
+                       break;
                }
        }
+       assert(_processor_after_last_custom_meter.lock());
 }
 
 boost::shared_ptr<Processor>