align stem-export (raw track outputs (with and w/p processing)
[ardour.git] / libs / ardour / route.cc
index 5335d69502c258970b91d1dc012ace0e05c79c0a..fa564968edc3df5dc93c52ef146152cacea2aba2 100644 (file)
@@ -84,8 +84,8 @@ PBD::Signal3<int,boost::shared_ptr<Route>, boost::shared_ptr<PluginInsert>, Rout
 
 /** Base class for all routable/mixable objects (tracks and busses) */
 Route::Route (Session& sess, string name, PresentationInfo::Flag flag, DataType default_type)
-       : GraphNode (sess._process_graph)
-       , Stripable (sess, name, PresentationInfo (flag))
+       : Stripable (sess, name, PresentationInfo (flag))
+       , GraphNode (sess._process_graph)
        , Muteable (sess, name)
        , Automatable (sess)
        , _active (true)
@@ -317,6 +317,8 @@ Route::process_output_buffers (BufferSet& bufs,
                return;
        }
 
+       _mute_control->automation_run (start_frame, nframes);
+
        /* figure out if we're going to use gain automation */
        if (gain_automation_ok) {
                _amp->set_gain_automation_buffer (_session.gain_automation_buffer ());
@@ -413,6 +415,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) {
 
@@ -442,8 +445,13 @@ Route::process_output_buffers (BufferSet& bufs,
                if (boost::dynamic_pointer_cast<Send>(*i) != 0) {
                        boost::dynamic_pointer_cast<Send>(*i)->set_delay_in(_signal_latency - latency);
                }
+               if (boost::dynamic_pointer_cast<PluginInsert>(*i) != 0) {
+                       const framecnt_t longest_session_latency = _initial_delay + _signal_latency;
+                       boost::dynamic_pointer_cast<PluginInsert>(*i)->set_sidechain_latency (
+                                       _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 ()) {
@@ -471,6 +479,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) {
@@ -493,7 +502,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());
                }
 
@@ -501,7 +510,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 ();
                }
@@ -1010,6 +1019,7 @@ Route::add_processors (const ProcessorList& others, boost::shared_ptr<Processor>
                        }
 
                        if ((*i)->active()) {
+                               // why?  emit  ActiveChanged() ??
                                (*i)->activate ();
                        }
 
@@ -1068,7 +1078,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 ();
@@ -1082,7 +1092,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 ();
@@ -1101,7 +1111,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);
                }
        }
 
@@ -1117,7 +1127,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);
                }
        }
 
@@ -1141,8 +1151,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);
@@ -1159,11 +1169,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 ());
                }
        }
 
@@ -1404,7 +1410,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) {
@@ -1448,7 +1454,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));
@@ -1617,8 +1623,8 @@ Route::try_configure_processors_unlocked (ChanCount in, ProcessorStreams* err)
 
                        if (boost::dynamic_pointer_cast<Delivery> (*p)
                                        && boost::dynamic_pointer_cast<Delivery> (*p)->role() == Delivery::Main
-                                       && !(is_monitor() || is_auditioner())
-                                       && ( _strict_io || Profile->get_mixbus ())) {
+                                       && !is_auditioner()
+                                       && (is_monitor() || _strict_io || Profile->get_mixbus ())) {
                                /* with strict I/O the panner + output are forced to
                                 * follow the last processor's output.
                                 *
@@ -1630,8 +1636,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 ());
@@ -1822,12 +1829,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 ();
@@ -2237,7 +2239,7 @@ Route::state(bool full_state)
        node->add_property("default-type", _default_type.to_string());
        node->add_property ("strict-io", _strict_io);
 
-       Stripable::add_state (*node);
+       node->add_child_nocopy (_presentation_info.get_state());
 
        node->add_property("active", _active?"yes":"no");
        string p;
@@ -2826,9 +2828,14 @@ 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
+                * not in new_order, it will be deleted and ~IO takes
+                * a process lock.
+                */
                _processors = new_order;
+               Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock ());
 
                if (must_configure) {
                        configure_processors_unlocked (0, &lm);
@@ -2878,6 +2885,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);
@@ -2890,7 +2899,7 @@ Route::silence_unlocked (framecnt_t nframes)
                                continue;
                        }
 
-                       (*i)->silence (nframes);
+                       (*i)->silence (nframes, now);
                }
 
                if (nframes == _session.get_block_size()) {
@@ -3420,13 +3429,19 @@ 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);
 
+       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);
+               }
+       }
        return 0;
 }
 
@@ -3460,11 +3475,17 @@ 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);
 
+       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);
+               }
+       }
        return 0;
 }
 
@@ -3695,7 +3716,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);
@@ -4498,8 +4521,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);
                }
        }