fix --disable-plugins (bypass ‘em all)
[ardour.git] / libs / ardour / route.cc
index 95c28ece8cc68a3f19d005d6499b52543d93bed7..36adbfa148f6b4e9442a5bb5495a80e78703e3f3 100644 (file)
@@ -47,6 +47,7 @@
 #include "ardour/internal_return.h"
 #include "ardour/internal_send.h"
 #include "ardour/meter.h"
+#include "ardour/delayline.h"
 #include "ardour/midi_buffer.h"
 #include "ardour/midi_port.h"
 #include "ardour/monitor_processor.h"
@@ -79,6 +80,7 @@ Route::Route (Session& sess, string name, Flag flg, DataType default_type)
        , GraphNode (sess._process_graph)
        , _active (true)
        , _signal_latency (0)
+       , _signal_latency_at_amp_position (0)
        , _initial_delay (0)
        , _roll_delay (0)
        , _flags (flg)
@@ -100,6 +102,7 @@ Route::Route (Session& sess, string name, Flag flg, DataType default_type)
        , _order_key (0)
        , _has_order_key (false)
        , _remote_control_id (0)
+       , _track_number (0)
        , _in_configure_processors (false)
        , _initial_io_setup (false)
        , _custom_meter_position_noted (false)
@@ -142,6 +145,13 @@ Route::init ()
        _output->changed.connect_same_thread (*this, boost::bind (&Route::output_change_handler, this, _1, _2));
        _output->PortCountChanging.connect_same_thread (*this, boost::bind (&Route::output_port_count_changing, this, _1));
 
+#if 0 // not used - just yet
+       if (!is_master() && !is_monitor() && !is_auditioner()) {
+               _delayline.reset (new DelayLine (_session, _name));
+               add_processor (_delayline, PreFader);
+       }
+#endif
+
        /* add amp processor  */
 
        _amp.reset (new Amp (_session));
@@ -423,12 +433,18 @@ Route::process_output_buffers (BufferSet& bufs,
        assert (!AudioEngine::instance()->process_lock().trylock());
 
        Glib::Threads::RWLock::ReaderLock lm (_processor_lock, Glib::Threads::TRY_LOCK);
-       assert(lm.locked());
+       if (!lm.locked()) {
+               bufs.silence (nframes, 0);
+               return;
+       }
 
        /* figure out if we're going to use gain automation */
        if (gain_automation_ok) {
                _amp->set_gain_automation_buffer (_session.gain_automation_buffer ());
-               _amp->setup_gain_automation (start_frame, end_frame, nframes);
+               _amp->setup_gain_automation (
+                               start_frame + _signal_latency_at_amp_position,
+                               end_frame + _signal_latency_at_amp_position,
+                               nframes);
        } else {
                _amp->apply_gain_automation (false);
        }
@@ -437,8 +453,13 @@ Route::process_output_buffers (BufferSet& bufs,
           on a transition between monitoring states we get a de-clicking gain
           change in the _main_outs delivery.
        */
+       bool silence = monitoring_state () == MonitoringSilence;
 
-       _main_outs->no_outs_cuz_we_no_monitor (monitoring_state () == MonitoringSilence);
+       //but we override this in the case where we have an internal generator
+       if ( _have_internal_generator )
+               silence = false;
+
+       _main_outs->no_outs_cuz_we_no_monitor (silence);
 
        /* -------------------------------------------------------------------------------------------
           GLOBAL DECLICK (for transport changes etc.)
@@ -506,6 +527,8 @@ Route::process_output_buffers (BufferSet& bufs,
        /* set this to be true if the meter will already have been ::run() earlier */
        bool const meter_already_run = metering_state() == MeteringInput;
 
+       framecnt_t latency = 0;
+
        for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
 
                if (meter_already_run && boost::dynamic_pointer_cast<PeakMeter> (*i)) {
@@ -531,20 +554,34 @@ Route::process_output_buffers (BufferSet& bufs,
                   do we catch route != active somewhere higher?
                */
 
-               (*i)->run (bufs, start_frame, end_frame, nframes, *i != _processors.back());
+               if (boost::dynamic_pointer_cast<Send>(*i) != 0) {
+                       boost::dynamic_pointer_cast<Send>(*i)->set_delay_in(_signal_latency - latency);
+               }
+
+               (*i)->run (bufs, start_frame - latency, end_frame - latency, nframes, *i != _processors.back());
                bufs.set_count ((*i)->output_streams());
+
+               if ((*i)->active ()) {
+                       latency += (*i)->signal_latency ();
+               }
        }
 }
 
 void
 Route::bounce_process (BufferSet& buffers, framepos_t start, framecnt_t nframes,
-                         boost::shared_ptr<Processor> endpoint, bool include_endpoint, bool for_export)
+               boost::shared_ptr<Processor> endpoint,
+               bool include_endpoint, bool for_export, bool for_freeze)
 {
        /* If no processing is required, there's no need to go any further. */
        if (!endpoint && !include_endpoint) {
                return;
        }
 
+       framecnt_t latency = bounce_get_latency(_amp, false, for_export, for_freeze);
+       _amp->set_gain_automation_buffer (_session.gain_automation_buffer ());
+       _amp->setup_gain_automation (start - latency, start - latency + nframes, nframes);
+
+       latency = 0;
        for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
 
                if (!include_endpoint && (*i) == endpoint) {
@@ -552,8 +589,10 @@ Route::bounce_process (BufferSet& buffers, framepos_t start, framecnt_t nframes,
                }
 
                /* if we're not exporting, stop processing if we come across a routing processor. */
-
-               if (!for_export && (*i)->does_routing()) {
+               if (!for_export && boost::dynamic_pointer_cast<PortInsert>(*i)) {
+                       break;
+               }
+               if (!for_export && for_freeze && (*i)->does_routing() && (*i)->active()) {
                        break;
                }
 
@@ -561,11 +600,11 @@ Route::bounce_process (BufferSet& buffers, framepos_t start, framecnt_t nframes,
                 * oh, and don't bother with the peak meter either.
                 */
                if (!(*i)->does_routing() && !boost::dynamic_pointer_cast<PeakMeter>(*i)) {
-                       (*i)->run (buffers, start, start+nframes, nframes, true);
+                       (*i)->run (buffers, start - latency, start - latency + nframes, nframes, true);
+                       buffers.set_count ((*i)->output_streams());
+                       latency += (*i)->signal_latency ();
                }
 
-               buffers.set_count ((*i)->output_streams());
-
                if ((*i) == endpoint) {
                        break;
                }
@@ -573,7 +612,8 @@ Route::bounce_process (BufferSet& buffers, framepos_t start, framecnt_t nframes,
 }
 
 framecnt_t
-Route::bounce_get_latency (boost::shared_ptr<Processor> endpoint, bool include_endpoint, bool for_export) const
+Route::bounce_get_latency (boost::shared_ptr<Processor> endpoint,
+               bool include_endpoint, bool for_export, bool for_freeze) const
 {
        framecnt_t latency = 0;
        if (!endpoint && !include_endpoint) {
@@ -581,11 +621,13 @@ Route::bounce_get_latency (boost::shared_ptr<Processor> endpoint, bool include_e
        }
 
        for (ProcessorList::const_iterator i = _processors.begin(); i != _processors.end(); ++i) {
-
                if (!include_endpoint && (*i) == endpoint) {
                        break;
                }
-               if (!for_export && (*i)->does_routing()) {
+               if (!for_export && boost::dynamic_pointer_cast<PortInsert>(*i)) {
+                       break;
+               }
+               if (!for_export && for_freeze && (*i)->does_routing() && (*i)->active()) {
                        break;
                }
                if (!(*i)->does_routing() && !boost::dynamic_pointer_cast<PeakMeter>(*i)) {
@@ -599,18 +641,21 @@ Route::bounce_get_latency (boost::shared_ptr<Processor> endpoint, bool include_e
 }
 
 ChanCount
-Route::bounce_get_output_streams (ChanCount &cc, boost::shared_ptr<Processor> endpoint, bool include_endpoint, bool for_export) const
+Route::bounce_get_output_streams (ChanCount &cc, boost::shared_ptr<Processor> endpoint,
+               bool include_endpoint, bool for_export, bool for_freeze) const
 {
        if (!endpoint && !include_endpoint) {
                return cc;
        }
 
        for (ProcessorList::const_iterator i = _processors.begin(); i != _processors.end(); ++i) {
-
                if (!include_endpoint && (*i) == endpoint) {
                        break;
                }
-               if (!for_export && (*i)->does_routing()) {
+               if (!for_export && boost::dynamic_pointer_cast<PortInsert>(*i)) {
+                       break;
+               }
+               if (!for_export && for_freeze && (*i)->does_routing() && (*i)->active()) {
                        break;
                }
                if (!(*i)->does_routing() && !boost::dynamic_pointer_cast<PeakMeter>(*i)) {
@@ -727,6 +772,11 @@ Route::set_solo (bool yn, void *src)
                return;
        }
 
+       if (is_master() || is_monitor() || is_auditioner()) {
+               DEBUG_TRACE (DEBUG::Solo, string_compose ("%1 ignore solo change (master, monitor or auditioner)\n", name()));
+               return;
+       }
+
        if (_route_group && src != _route_group && _route_group->is_active() && _route_group->is_solo()) {
                _route_group->foreach_route (boost::bind (&Route::set_solo, _1, yn, _route_group));
                return;
@@ -1172,8 +1222,18 @@ Route::add_processor_from_xml_2X (const XMLNode& node, int version)
                if (processor->set_state (node, version)) {
                        return false;
                }
+               
+               //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() )
+                                       processor->activate();
+                               else
+                                       processor->deactivate();
+                       }
+               }
 
-               return (add_processor (processor, placement) == 0);
+               return (add_processor (processor, placement, 0, false) == 0);
        }
 
        catch (failed_constructor &err) {
@@ -1420,7 +1480,7 @@ Route::clear_processors (Placement p)
                                seen_amp = true;
                        }
 
-                       if ((*i) == _amp || (*i) == _meter || (*i) == _main_outs) {
+                       if ((*i) == _amp || (*i) == _meter || (*i) == _main_outs || (*i) == _delayline) {
 
                                /* you can't remove these */
 
@@ -1487,7 +1547,7 @@ Route::remove_processor (boost::shared_ptr<Processor> processor, ProcessorStream
 
        /* these can never be removed */
 
-       if (processor == _amp || processor == _meter || processor == _main_outs) {
+       if (processor == _amp || processor == _meter || processor == _main_outs || processor == _delayline) {
                return 0;
        }
 
@@ -1604,7 +1664,7 @@ Route::remove_processors (const ProcessorList& to_be_deleted, ProcessorStreams*
 
                        /* these can never be removed */
 
-                       if (processor == _amp || processor == _meter || processor == _main_outs) {
+                       if (processor == _amp || processor == _meter || processor == _main_outs || processor == _delayline) {
                                ++i;
                                continue;
                        }
@@ -1993,6 +2053,10 @@ Route::state(bool full_state)
        node->add_child_nocopy (_mute_control->get_state ());
        node->add_child_nocopy (_mute_master->get_state ());
 
+       if (full_state) {
+               node->add_child_nocopy (Automatable::get_automation_xml_state ());
+       }
+
        XMLNode* remote_control_node = new XMLNode (X_("RemoteControl"));
        snprintf (buf, sizeof (buf), "%d", _remote_control_id);
        remote_control_node->add_property (X_("id"), buf);
@@ -2263,6 +2327,9 @@ Route::set_state (const XMLNode& node, int version)
 
                } else if (child->name() == X_("MuteMaster")) {
                        _mute_master->set_state (*child, version);
+
+               } else if (child->name() == Automatable::xml_node_name) {
+                       set_automation_xml_state (*child, Evoral::Parameter(NullAutomation));
                }
        }
 
@@ -2272,6 +2339,7 @@ Route::set_state (const XMLNode& node, int version)
 int
 Route::set_state_2X (const XMLNode& node, int version)
 {
+       LocaleGuard lg (X_("C"));
        XMLNodeList nlist;
        XMLNodeConstIterator niter;
        XMLNode *child;
@@ -2569,6 +2637,11 @@ Route::set_processor_state (const XMLNode& node)
                } else if (prop->value() == "meter") {
                        _meter->set_state (**niter, Stateful::current_state_version);
                        new_order.push_back (_meter);
+               } else if (prop->value() == "delay") {
+                       if (_delayline) {
+                               _delayline->set_state (**niter, Stateful::current_state_version);
+                               new_order.push_back (_delayline);
+                       }
                } else if (prop->value() == "main-outs") {
                        _main_outs->set_state (**niter, Stateful::current_state_version);
                } else if (prop->value() == "intreturn") {
@@ -2606,7 +2679,7 @@ Route::set_processor_state (const XMLNode& node)
 
                                if (prop->value() == "intsend") {
 
-                                       processor.reset (new InternalSend (_session, _pannable, _mute_master, boost::shared_ptr<Route>(), Delivery::Aux, true));
+                                       processor.reset (new InternalSend (_session, _pannable, _mute_master, boost::dynamic_pointer_cast<ARDOUR::Route>(shared_from_this()), boost::shared_ptr<Route>(), Delivery::Aux, true));
 
                                } else if (prop->value() == "ladspa" || prop->value() == "Ladspa" ||
                                           prop->value() == "lv2" ||
@@ -2775,7 +2848,7 @@ Route::enable_monitor_send ()
 
        /* make sure we have one */
        if (!_monitor_send) {
-               _monitor_send.reset (new InternalSend (_session, _pannable, _mute_master, _session.monitor_out(), Delivery::Listen));
+               _monitor_send.reset (new InternalSend (_session, _pannable, _mute_master, boost::dynamic_pointer_cast<ARDOUR::Route>(shared_from_this()), _session.monitor_out(), Delivery::Listen));
                _monitor_send->set_display_to_user (false);
        }
 
@@ -2813,7 +2886,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, route, Delivery::Aux));
+                       listener.reset (new InternalSend (_session, sendpan, _mute_master, boost::dynamic_pointer_cast<ARDOUR::Route>(shared_from_this()), route, Delivery::Aux));
                }
 
                add_processor (listener, before);
@@ -3279,15 +3352,24 @@ framecnt_t
 Route::update_signal_latency ()
 {
        framecnt_t l = _output->user_latency();
+       framecnt_t lamp = 0;
+       bool before_amp = true;
 
        for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
                if ((*i)->active ()) {
                        l += (*i)->signal_latency ();
                }
+               if ((*i) == _amp) {
+                       before_amp = false;
+               }
+               if (before_amp) {
+                       lamp = l;
+               }
        }
 
        DEBUG_TRACE (DEBUG::Latency, string_compose ("%1: internal signal latency = %2\n", _name, l));
 
+       _signal_latency_at_amp_position = lamp;
        if (_signal_latency != l) {
                _signal_latency = l;
                signal_latency_changed (); /* EMIT SIGNAL */
@@ -3329,18 +3411,21 @@ Route::set_latency_compensation (framecnt_t longest_session_latency)
 }
 
 Route::SoloControllable::SoloControllable (std::string name, boost::shared_ptr<Route> r)
-       : AutomationControl (r->session(), Evoral::Parameter (SoloAutomation),
-                            boost::shared_ptr<AutomationList>(), name)
+       : AutomationControl (r->session(),
+                            Evoral::Parameter (SoloAutomation),
+                            ParameterDescriptor(Evoral::Parameter (SoloAutomation)),
+                            boost::shared_ptr<AutomationList>(), name)
        , _route (r)
 {
        boost::shared_ptr<AutomationList> gl(new AutomationList(Evoral::Parameter(SoloAutomation)));
+       gl->set_interpolation(Evoral::ControlList::Discrete);
        set_list (gl);
 }
 
 void
 Route::SoloControllable::set_value (double val)
 {
-       bool bval = ((val >= 0.5f) ? true: false);
+       const bool bval = ((val >= 0.5) ? true : false);
 
        boost::shared_ptr<RouteList> rl (new RouteList);
 
@@ -3374,39 +3459,64 @@ Route::SoloControllable::get_value () const
 }
 
 Route::MuteControllable::MuteControllable (std::string name, boost::shared_ptr<Route> r)
-       : AutomationControl (r->session(), Evoral::Parameter (MuteAutomation),
-                            boost::shared_ptr<AutomationList>(), name)
+       : AutomationControl (r->session(),
+                            Evoral::Parameter (MuteAutomation),
+                            ParameterDescriptor (Evoral::Parameter (MuteAutomation)),
+                            boost::shared_ptr<AutomationList>(),
+                            name)
        , _route (r)
 {
        boost::shared_ptr<AutomationList> gl(new AutomationList(Evoral::Parameter(MuteAutomation)));
+       gl->set_interpolation(Evoral::ControlList::Discrete);
        set_list (gl);
 }
 
 void
-Route::MuteControllable::set_value (double val)
+Route::MuteControllable::set_superficial_value(bool muted)
 {
-       bool bval = ((val >= 0.5f) ? true: false);
+       /* Note we can not use AutomationControl::set_value here since it will emit
+          Changed(), but the value will not be correct to the observer. */
 
-       boost::shared_ptr<RouteList> rl (new RouteList);
+       bool to_list = _list && ((AutomationList*)_list.get())->automation_write();
+
+       Control::set_double (muted, _session.transport_frame(), to_list);
+}
+
+void
+Route::MuteControllable::set_value (double val)
+{
+       const bool bval = ((val >= 0.5) ? true : false);
 
        boost::shared_ptr<Route> r = _route.lock ();
        if (!r) {
                return;
        }
 
-       rl->push_back (r);
-       _session.set_mute (rl, bval);
+       if (_list && ((AutomationList*)_list.get())->automation_playback()) {
+               // Playing back automation, set route mute directly
+               r->set_mute (bval, this);
+       } else {
+               // Set from user, queue mute event
+               boost::shared_ptr<RouteList> rl (new RouteList);
+               rl->push_back (r);
+               _session.set_mute (rl, bval, Session::rt_cleanup);
+       }
+
+       // Set superficial/automation value to drive controller (and possibly record)
+       set_superficial_value(bval);
 }
 
 double
 Route::MuteControllable::get_value () const
 {
-       boost::shared_ptr<Route> r = _route.lock ();
-       if (!r) {
-               return 0;
+       if (_list && ((AutomationList*)_list.get())->automation_playback()) {
+               // Playing back automation, get the value from the list
+               return AutomationControl::get_value();
        }
 
-       return r->muted() ? 1.0f : 0.0f;
+       // Not playing back automation, get the actual route mute value
+       boost::shared_ptr<Route> r = _route.lock ();
+       return (r && r->muted()) ? 1.0 : 0.0;
 }
 
 void
@@ -3516,14 +3626,14 @@ Route::save_as_template (const string& path, const string& name)
 bool
 Route::set_name (const string& str)
 {
-       bool ret;
-       string ioproc_name;
-       string name;
+       if (str == name()) {
+               return true;
+       }
 
-       name = Route::ensure_track_or_route_name (str, _session);
+       string name = Route::ensure_track_or_route_name (str, _session);
        SessionObject::set_name (name);
 
-       ret = (_input->set_name(name) && _output->set_name(name));
+       bool ret = (_input->set_name(name) && _output->set_name(name));
 
        if (ret) {
                /* rename the main outs. Leave other IO processors
@@ -3648,6 +3758,10 @@ Route::denormal_protection () const
 void
 Route::set_active (bool yn, void* src)
 {
+       if (_session.transport_rolling()) {
+               return;
+       }
+
        if (_route_group && src != _route_group && _route_group->is_active() && _route_group->is_route_active()) {
                _route_group->foreach_route (boost::bind (&Route::set_active, _1, yn, _route_group));
                return;
@@ -3665,7 +3779,7 @@ Route::set_active (bool yn, void* src)
 void
 Route::meter ()
 {
-       Glib::Threads::RWLock::ReaderLock rm (_processor_lock, Glib::Threads::TRY_LOCK);
+       Glib::Threads::RWLock::ReaderLock rm (_processor_lock);
 
        assert (_meter);
 
@@ -3720,7 +3834,7 @@ Route::get_control (const Evoral::Parameter& param)
 
                /* maybe one of our processors does or ... */
 
-               Glib::Threads::RWLock::ReaderLock rm (_processor_lock, Glib::Threads::TRY_LOCK);
+               Glib::Threads::RWLock::ReaderLock rm (_processor_lock);
                for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
                        if ((c = boost::dynamic_pointer_cast<AutomationControl>((*i)->control (param))) != 0) {
                                break;
@@ -4090,6 +4204,12 @@ Route::setup_invisible_processors ()
                }
        }
 
+#if 0 // not used - just yet
+       if (!is_master() && !is_monitor() && !is_auditioner()) {
+               new_processors.push_front (_delayline);
+       }
+#endif
+
        /* MONITOR CONTROL */
 
        if (_monitor_control && is_monitor ()) {
@@ -4246,6 +4366,10 @@ Route::non_realtime_locate (framepos_t pos)
                _pannable->transport_located (pos);
        }
 
+       if (_delayline.get()) {
+               _delayline.get()->flush();
+       }
+
        {
                //Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock ());
                Glib::Threads::RWLock::ReaderLock lm (_processor_lock);