NO-OP: whitespace
[ardour.git] / libs / ardour / session.cc
index b903ed66fc07da41ab14811fda88816b7044803a..654234c51566d7a58618b48701ad3baa9db7cae9 100644 (file)
 #include "ardour/revision.h"
 #include "ardour/route_graph.h"
 #include "ardour/route_group.h"
+#include "ardour/rt_tasklist.h"
 #include "ardour/send.h"
 #include "ardour/selection.h"
 #include "ardour/session.h"
 #include "ardour/session_directory.h"
 #include "ardour/session_playlists.h"
-#include "ardour/slave.h"
 #include "ardour/smf_source.h"
-#include "ardour/slave.h"
 #include "ardour/solo_isolate_control.h"
 #include "ardour/source_factory.h"
 #include "ardour/speakers.h"
 #include "ardour/tempo.h"
 #include "ardour/ticker.h"
+#include "ardour/transport_master.h"
 #include "ardour/track.h"
 #include "ardour/types_convert.h"
 #include "ardour/user_bundle.h"
@@ -184,22 +184,21 @@ Session::Session (AudioEngine &eng,
        , _seek_counter (0)
        , _session_range_location (0)
        , _session_range_end_is_free (true)
-       , _slave (0)
        , _silent (false)
+       , _remaining_latency_preroll (0)
+       , _engine_speed (1.0)
        , _transport_speed (0)
        , _default_transport_speed (1.0)
        , _last_transport_speed (0)
        , _signalled_varispeed (0)
        , _target_transport_speed (0.0)
        , auto_play_legal (false)
-       , _last_slave_transport_sample (0)
-       , maximum_output_latency (0)
        , _requested_return_sample (-1)
        , current_block_size (0)
        , _worst_output_latency (0)
        , _worst_input_latency (0)
-       , _worst_track_latency (0)
-       , _worst_track_out_latency (0)
+       , _worst_route_latency (0)
+       , _send_latency_changes (0)
        , _have_captured (false)
        , _non_soloed_outs_muted (false)
        , _listening (false)
@@ -209,13 +208,8 @@ Session::Session (AudioEngine &eng,
        , _was_seamless (Config->get_seamless_loop ())
        , _under_nsm_control (false)
        , _xrun_count (0)
-       , delta_accumulator_cnt (0)
-       , average_slave_delta (1800) // !!! why 1800 ???
-       , average_dir (0)
-       , have_first_delta_accumulator (false)
-       , _slave_state (Stopped)
-       , _mtc_active (false)
-       , _ltc_active (false)
+       , transport_master_tracking_state (Stopped)
+       , master_wait_end (0)
        , post_export_sync (false)
        , post_export_position (0)
        , _exporting (false)
@@ -223,7 +217,6 @@ Session::Session (AudioEngine &eng,
        , _realtime_export (false)
        , _region_export (false)
        , _export_preroll (0)
-       , _export_latency (0)
        , _pre_export_mmc_enabled (false)
        , _name (snapshot_name)
        , _is_new (true)
@@ -242,10 +235,6 @@ Session::Session (AudioEngine &eng,
        , _last_roll_location (0)
        , _last_roll_or_reversal_location (0)
        , _last_record_location (0)
-       , pending_locate_roll (false)
-       , pending_locate_sample (0)
-       , pending_locate_flush (false)
-       , pending_abort (false)
        , pending_auto_loop (false)
        , _mempool ("Session", 3145728)
        , lua (lua_newstate (&PBD::ReallocPool::lalloc, &_mempool))
@@ -312,7 +301,6 @@ Session::Session (AudioEngine &eng,
        , _play_range (false)
        , _range_selection (-1,-1)
        , _object_selection (-1,-1)
-       , _preroll_record_punch_pos (-1)
        , _preroll_record_trim_len (0)
        , _count_in_once (false)
        , main_outs (0)
@@ -463,6 +451,8 @@ Session::Session (AudioEngine &eng,
        StartTimeChanged.connect_same_thread (*this, boost::bind (&Session::start_time_changed, this, _1));
        EndTimeChanged.connect_same_thread (*this, boost::bind (&Session::end_time_changed, this, _1));
 
+       Send::ChangedLatency.connect_same_thread (*this, boost::bind (&Session::send_latency_compensation_change, this));
+
        emit_thread_start ();
        auto_connect_thread_start ();
 
@@ -599,6 +589,8 @@ Session::immediately_post_engine ()
         * session or set state for an existing one.
         */
 
+       _rt_tasklist.reset (new RTTaskList ());
+
        if (how_many_dsp_threads () > 1) {
                /* For now, only create the graph if we are using >1 DSP threads, as
                   it is a bit slower than the old code with 1 thread.
@@ -656,8 +648,6 @@ Session::destroy ()
        {
                Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
                ltc_tx_cleanup();
-               delete _slave;
-               _slave = 0;
        }
 
        /* disconnect from any and all signals that we are connected to */
@@ -671,7 +661,6 @@ Session::destroy ()
 
        /* remove I/O objects before unsetting the engine session */
        _click_io.reset ();
-       _ltc_input.reset ();
        _ltc_output.reset ();
 
        ControlProtocolManager::instance().drop_protocols ();
@@ -687,12 +676,6 @@ Session::destroy ()
        EngineStateController::instance()->remove_session();
 #endif
 
-       /* drop slave, if any. We don't use use_sync_source (0) because
-        * there's no reason to do all the other stuff that may happen
-        * when calling that method.
-        */
-       delete _slave;
-
        /* deregister all ports - there will be no process or any other
         * callbacks from the engine any more.
         */
@@ -846,11 +829,9 @@ Session::destroy ()
                bool del = true;
                switch (ev->type) {
                        case SessionEvent::AutoLoop:
-                       case SessionEvent::AutoLoopDeclick:
                        case SessionEvent::Skip:
                        case SessionEvent::PunchIn:
                        case SessionEvent::PunchOut:
-                       case SessionEvent::RecordStart:
                        case SessionEvent::StopOnce:
                        case SessionEvent::RangeStop:
                        case SessionEvent::RangeLocate:
@@ -893,21 +874,8 @@ Session::setup_ltc ()
 {
        XMLNode* child = 0;
 
-       _ltc_input.reset (new IO (*this, X_("LTC In"), IO::Input));
        _ltc_output.reset (new IO (*this, X_("LTC Out"), IO::Output));
 
-       if (state_tree && (child = find_named_node (*state_tree->root(), X_("LTC In"))) != 0) {
-               _ltc_input->set_state (*(child->children().front()), Stateful::loading_state_version);
-       } else {
-               {
-                       Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
-                       _ltc_input->ensure_io (ChanCount (DataType::AUDIO, 1), true, this);
-                       // TODO use auto-connect thread somehow (needs a route currently)
-                       // see note in Session::auto_connect_thread_run() why process lock is needed.
-                       reconnect_ltc_input ();
-               }
-       }
-
        if (state_tree && (child = find_named_node (*state_tree->root(), X_("LTC Out"))) != 0) {
                _ltc_output->set_state (*(child->children().front()), Stateful::loading_state_version);
        } else {
@@ -923,7 +891,6 @@ Session::setup_ltc ()
         * IO style of NAME/TYPE-{in,out}N
         */
 
-       _ltc_input->nth (0)->set_name (X_("LTC-in"));
        _ltc_output->nth (0)->set_name (X_("LTC-out"));
 }
 
@@ -1656,7 +1623,7 @@ Session::auto_punch_start_changed (Location* location)
 {
        replace_event (SessionEvent::PunchIn, location->start());
 
-       if (get_record_enabled() && config.get_punch_in()) {
+       if (get_record_enabled() && config.get_punch_in() && !actively_recording ()) {
                /* capture start has been changed, so save new pending state */
                save_state ("", true);
        }
@@ -1665,19 +1632,14 @@ Session::auto_punch_start_changed (Location* location)
 void
 Session::auto_punch_end_changed (Location* location)
 {
-       samplepos_t when_to_stop = location->end();
-       // when_to_stop += _worst_output_latency + _worst_input_latency;
-       replace_event (SessionEvent::PunchOut, when_to_stop);
+       replace_event (SessionEvent::PunchOut, location->end());
 }
 
 void
 Session::auto_punch_changed (Location* location)
 {
-       samplepos_t when_to_stop = location->end();
-
-       replace_event (SessionEvent::PunchIn, location->start());
-       //when_to_stop += _worst_output_latency + _worst_input_latency;
-       replace_event (SessionEvent::PunchOut, when_to_stop);
+       auto_punch_start_changed (location);
+       auto_punch_end_changed (location);
 }
 
 /** @param loc A loop location.
@@ -1699,34 +1661,17 @@ Session::auto_loop_changed (Location* location)
        samplecnt_t dcl;
        auto_loop_declick_range (location, dcp, dcl);
 
-       if (transport_rolling() && play_loop) {
-
-               replace_event (SessionEvent::AutoLoopDeclick, dcp, dcl);
+       bool rolling = transport_rolling ();
 
-               // if (_transport_sample > location->end()) {
+       if (rolling && play_loop) {
 
                if (_transport_sample < location->start() || _transport_sample > location->end()) {
                        // relocate to beginning of loop
                        clear_events (SessionEvent::LocateRoll);
-
                        request_locate (location->start(), true);
 
                }
-               else if (Config->get_seamless_loop() && !loop_changing) {
-
-                       // schedule a locate-roll to refill the disk readers at the
-                       // previous loop end
-                       loop_changing = true;
-
-                       if (location->end() > last_loopend) {
-                               clear_events (SessionEvent::LocateRoll);
-                               SessionEvent *ev = new SessionEvent (SessionEvent::LocateRoll, SessionEvent::Add, last_loopend, last_loopend, 0, true);
-                               queue_event (ev);
-                       }
-
-               }
        } else {
-               clear_events (SessionEvent::AutoLoopDeclick);
                clear_events (SessionEvent::AutoLoop);
        }
 
@@ -1736,13 +1681,12 @@ Session::auto_loop_changed (Location* location)
 
        samplepos_t pos;
 
-       if (!transport_rolling() && select_playhead_priority_target (pos)) {
+       if (!rolling && select_playhead_priority_target (pos)) {
                if (pos == location->start()) {
                        request_locate (pos);
                }
        }
 
-
        last_loopend = location->end();
        set_dirty ();
 }
@@ -1755,7 +1699,7 @@ Session::set_auto_punch_location (Location* location)
        if ((existing = _locations->auto_punch_location()) != 0 && existing != location) {
                punch_connections.drop_connections();
                existing->set_auto_punch (false, this);
-               remove_event (existing->start(), SessionEvent::PunchIn);
+               clear_events (SessionEvent::PunchIn);
                clear_events (SessionEvent::PunchOut);
                auto_punch_location_changed (0);
        }
@@ -1815,7 +1759,6 @@ Session::set_auto_loop_location (Location* location)
                samplepos_t dcp;
                samplecnt_t dcl;
                auto_loop_declick_range (existing, dcp, dcl);
-               remove_event (dcp, SessionEvent::AutoLoopDeclick);
                auto_loop_location_changed (0);
        }
 
@@ -2010,24 +1953,24 @@ Session::location_added (Location *location)
 void
 Session::location_removed (Location *location)
 {
-        if (location->is_auto_loop()) {
-               set_auto_loop_location (0);
-               set_track_loop (false);
-        }
+       if (location->is_auto_loop()) {
+               set_auto_loop_location (0);
+               set_track_loop (false);
+       }
 
-        if (location->is_auto_punch()) {
-                set_auto_punch_location (0);
-        }
+       if (location->is_auto_punch()) {
+               set_auto_punch_location (0);
+       }
 
-        if (location->is_session_range()) {
-                /* this is never supposed to happen */
-                error << _("programming error: session range removed!") << endl;
-        }
+       if (location->is_session_range()) {
+               /* this is never supposed to happen */
+               error << _("programming error: session range removed!") << endl;
+       }
 
-        if (location->is_skip()) {
+       if (location->is_skip()) {
 
-                update_skips (location, false);
-        }
+               update_skips (location, false);
+       }
 
        set_dirty ();
 }
@@ -2119,7 +2062,6 @@ Session::disable_record (bool rt_context, bool force)
                if (!rt_context) {
                        remove_pending_capture_state ();
                }
-               unset_preroll_record_punch ();
        }
 }
 
@@ -2157,7 +2099,7 @@ Session::maybe_enable_record (bool rt_context)
        }
 
        if (_transport_speed) {
-               if (!config.get_punch_in() && !preroll_record_punch_enabled ()) {
+               if (!config.get_punch_in()) {
                        enable_record ();
                }
        } else {
@@ -2171,14 +2113,12 @@ Session::maybe_enable_record (bool rt_context)
 samplepos_t
 Session::audible_sample (bool* latent_locate) const
 {
-       samplepos_t ret;
-
-       sampleoffset_t offset = worst_playback_latency (); // - _engine.samples_since_cycle_start ();
-       offset *= transport_speed ();
        if (latent_locate) {
                *latent_locate = false;
        }
 
+       samplepos_t ret;
+
        if (synced_to_engine()) {
                /* Note: this is basically just sync-to-JACK */
                ret = _engine.transport_sample();
@@ -2186,57 +2126,37 @@ Session::audible_sample (bool* latent_locate) const
                ret = _transport_sample;
        }
 
-       if (transport_rolling()) {
-               ret -= offset;
+       assert (ret >= 0);
 
-               /* Check to see if we have passed the first guaranteed
-                * audible sample past our last start position. if not,
-                * return that last start point because in terms
-                * of audible samples, we have not moved yet.
-                *
-                * `Start position' in this context means the time we last
-                * either started, located, or changed transport direction.
-                */
-
-               if (_transport_speed > 0.0f) {
+       if (!transport_rolling()) {
+               return ret;
+       }
 
-                       if (!play_loop || !have_looped) {
-                               if (ret < _last_roll_or_reversal_location) {
-                                       if (latent_locate) {
-                                               *latent_locate = true;
-                                       }
-                                       return _last_roll_or_reversal_location;
-                               }
-                       } else {
-                               /* the play-position wrapped at the loop-point
-                                * ardour is already playing the beginning of the loop,
-                                * but due to playback latency, the "audible frame"
-                                * is still at the end of the loop.
-                                */
-                               Location *location = _locations->auto_loop_location();
-                               sampleoffset_t lo = location->start() - ret;
-                               if (lo > 0) {
-                                       ret = location->end () - lo;
-                                       if (latent_locate) {
-                                               *latent_locate = true;
-                                       }
+#if 0 // TODO looping
+       if (_transport_speed > 0.0f) {
+               if (play_loop && have_looped) {
+                       /* the play-position wrapped at the loop-point
+                        * ardour is already playing the beginning of the loop,
+                        * but due to playback latency, the "audible frame"
+                        * is still at the end of the loop.
+                        */
+                       Location *location = _locations->auto_loop_location();
+                       sampleoffset_t lo = location->start() - ret;
+                       if (lo > 0) {
+                               ret = location->end () - lo;
+                               if (latent_locate) {
+                                       *latent_locate = true;
                                }
                        }
-
-               } else if (_transport_speed < 0.0f) {
-
-                       /* XXX wot? no backward looping? */
-
-                       if (ret > _last_roll_or_reversal_location) {
-                               return _last_roll_or_reversal_location;
-                       }
                }
+       } else if (_transport_speed < 0.0f) {
+               /* XXX wot? no backward looping? */
        }
+#endif
 
        return std::max ((samplepos_t)0, ret);
 }
 
-
 samplecnt_t
 Session::preroll_samples (samplepos_t pos) const
 {
@@ -3052,40 +2972,6 @@ Session::reconnect_midi_scene_ports(bool inputs)
     }
 }
 
-void
-Session::reconnect_mtc_ports ()
-{
-       boost::shared_ptr<MidiPort> mtc_in_ptr = _midi_ports->mtc_input_port();
-
-       if (!mtc_in_ptr) {
-               return;
-       }
-
-       mtc_in_ptr->disconnect_all ();
-
-       std::vector<EngineStateController::MidiPortState> midi_port_states;
-       EngineStateController::instance()->get_physical_midi_input_states (midi_port_states);
-
-       std::vector<EngineStateController::MidiPortState>::iterator state_iter = midi_port_states.begin();
-
-       for (; state_iter != midi_port_states.end(); ++state_iter) {
-               if (state_iter->available && state_iter->mtc_in) {
-                       mtc_in_ptr->connect (state_iter->name);
-               }
-       }
-
-       if (!_midi_ports->mtc_input_port ()->connected () &&
-           config.get_external_sync () &&
-           (Config->get_sync_source () == MTC) ) {
-               config.set_external_sync (false);
-       }
-
-       if ( ARDOUR::Profile->get_trx () ) {
-               // Tracks need this signal to update timecode_source_dropdown
-               MtcOrLtcInputPortChanged (); //emit signal
-       }
-}
-
 void
 Session::reconnect_mmc_ports(bool inputs)
 {
@@ -3437,7 +3323,7 @@ Session::new_route_from_template (uint32_t how_many, PresentationInfo::order_t i
                        }
 
                        /* set this name in the XML description that we are about to use */
-
+#warning fixme -- no more Diskstream
                        if (pd == CopyPlaylist) {
                                XMLNode* ds_node = find_named_node (node_copy, "Diskstream");
                                if (ds_node) {
@@ -3505,9 +3391,7 @@ Session::new_route_from_template (uint32_t how_many, PresentationInfo::order_t i
                                                (*i)->remove_property (X_("bitslot"));
                                        }
                                        else if (type && type->value() == X_("port")) {
-                                               // PortInsert::set_state() handles the bitslot
-                                               (*i)->remove_property (X_("bitslot"));
-                                               (*i)->set_property ("ignore-name", "1");
+                                               IOProcessor::prepare_for_reset (**i, name);
                                        }
                                }
                        }
@@ -4364,6 +4248,16 @@ Session::get_stripables () const
        return rv;
 }
 
+RouteList
+Session::get_routelist (bool mixer_order) const
+{
+       boost::shared_ptr<RouteList> r = routes.reader ();
+       RouteList rv;
+       rv.insert (rv.end(), r->begin(), r->end());
+       rv.sort (Stripable::Sorter (mixer_order));
+       return rv;
+}
+
 boost::shared_ptr<RouteList>
 Session::get_routes_with_internal_returns() const
 {
@@ -5521,7 +5415,6 @@ Session::setup_lua ()
 #ifndef NDEBUG
        lua.Print.connect (&_lua_print);
 #endif
-       lua.tweak_rt_gc ();
        lua.sandbox (true);
        lua.do_command (
                        "function ArdourSession ()"
@@ -5652,9 +5545,11 @@ Session::setup_lua ()
                abort(); /*NOTREACHED*/
        }
 
+       lua_mlock (L, 1);
        LuaBindings::stddef (L);
        LuaBindings::common (L);
        LuaBindings::dsp (L);
+       lua_mlock (L, 0);
        luabridge::push <Session *> (L, this);
        lua_setglobal (L, "Session");
 }
@@ -5739,16 +5634,9 @@ Session::graph_reordered ()
        resort_routes ();
 
        /* force all diskstreams to update their capture offset values to
-          reflect any changes in latencies within the graph.
-       */
-
-       boost::shared_ptr<RouteList> rl = routes.reader ();
-       for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
-               boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
-               if (tr) {
-                       tr->update_latency_information ();
-               }
-       }
+        * reflect any changes in latencies within the graph.
+        */
+       update_route_latency (false, true);
 }
 
 /** @return Number of samples that there is disk space available to write,
@@ -6857,104 +6745,110 @@ Session::unknown_processors () const
        return p;
 }
 
-/* this is always called twice, first for playback (true), then for capture */
 void
-Session::update_latency (bool playback)
+Session::set_worst_io_latencies_x (IOChange, void *)
 {
+               set_worst_io_latencies ();
+}
 
-       DEBUG_TRACE (DEBUG::Latency, string_compose ("JACK latency callback: %1\n", (playback ? "PLAYBACK" : "CAPTURE")));
-
-       if ((_state_of_the_state & (InitialConnecting|Deletion)) || _adding_routes_in_progress || _route_deletion_in_progress) {
-               return;
-       }
-       if (!_engine.running()) {
-               return;
-       }
+void
+Session::send_latency_compensation_change ()
+{
+       /* As a result of Send::set_output_latency()
+        * or InternalReturn::set_playback_offset ()
+        * the send's own latency can change (source track
+        * is aligned with target bus).
+        *
+        * This can only happen be triggered by
+        * Route::update_signal_latency ()
+        * when updating the processor latency.
+        *
+        * We need to walk the graph again to take those changes into account
+        * (we should probably recurse or process the graph in a 2 step process).
+        */
+       ++_send_latency_changes;
+}
 
-       /* Note; RouteList is sorted as process-graph */
+bool
+Session::update_route_latency (bool playback, bool apply_to_delayline)
+{
+       /* Note: RouteList is process-graph sorted */
        boost::shared_ptr<RouteList> r = routes.reader ();
-       samplecnt_t max_latency = 0;
 
        if (playback) {
-               /* reverse the list so that we work backwards from the last route to run to the first */
+               /* reverse the list so that we work backwards from the last route to run to the first,
+                * this is not needed, but can help to reduce the iterations for aux-sends.
+                */
                RouteList* rl = routes.reader().get();
                r.reset (new RouteList (*rl));
                reverse (r->begin(), r->end());
        }
 
-       /* compute actual latency values for the given direction and store them all in per-port
-        * structures. this will also publish the same values (to JACK) so that computation of latency
-        * for routes can consistently use public latency values.
-        */
+       bool changed = false;
+       int bailout = 0;
+restart:
+       _send_latency_changes = 0;
+       _worst_route_latency = 0;
 
        for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
-               max_latency = max (max_latency, (*i)->set_private_port_latencies (playback));
+               // if (!(*i)->active()) { continue ; } // TODO
+               samplecnt_t l;
+               if ((*i)->signal_latency () != (l = (*i)->update_signal_latency (apply_to_delayline))) {
+                       changed = true;
+               }
+               _worst_route_latency = std::max (l, _worst_route_latency);
        }
 
-       /* because we latency compensate playback, our published playback latencies should
-        * be the same for all output ports - all material played back by ardour has
-        * the same latency, whether its caused by plugins or by latency compensation. since
-        * these may differ from the values computed above, reset all playback port latencies
-        * to the same value.
-        */
-
-       DEBUG_TRACE (DEBUG::Latency, string_compose ("Set public port latencies to %1\n", max_latency));
-
-       for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
-               (*i)->set_public_port_latencies (max_latency, playback);
+       if (_send_latency_changes > 0) {
+               // only 1 extra iteration is needed (we allow only 1 level of aux-sends)
+               // BUT..  jack'n'sends'n'bugs
+               if (++bailout < 5) {
+                       cerr << "restarting Session::update_latency. # of send changes: " << _send_latency_changes << " iteration: " << bailout << endl;
+                       goto restart;
+               }
        }
 
-       if (playback) {
-
-               post_playback_latency ();
-
-       } else {
-
-               post_capture_latency ();
-       }
+       DEBUG_TRACE (DEBUG::Latency, string_compose ("worst signal processing latency: %1 (changed ? %2)\n", _worst_route_latency, (changed ? "yes" : "no")));
 
-       DEBUG_TRACE (DEBUG::Latency, "JACK latency callback: DONE\n");
+       return changed;
 }
 
 void
-Session::post_playback_latency ()
+Session::update_latency (bool playback)
 {
-       set_worst_playback_latency ();
+       DEBUG_TRACE (DEBUG::Latency, string_compose ("JACK latency callback: %1\n", (playback ? "PLAYBACK" : "CAPTURE")));
 
-       boost::shared_ptr<RouteList> r = routes.reader ();
+       if ((_state_of_the_state & (InitialConnecting|Deletion)) || _adding_routes_in_progress || _route_deletion_in_progress) {
+               return;
+       }
+       if (!_engine.running()) {
+               return;
+       }
 
-       _worst_track_out_latency = 0;
+       /* Note; RouteList is sorted as process-graph */
+       boost::shared_ptr<RouteList> r = routes.reader ();
 
-       for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
-               assert (!(*i)->is_auditioner()); // XXX remove me
-               if (!(*i)->active()) { continue ; }
-               _worst_track_latency = max (_worst_track_latency, (*i)->update_signal_latency ());
-               if (boost::dynamic_pointer_cast<Track> (*i)) {
-                       _worst_track_out_latency = max (_worst_track_out_latency, (*i)->output ()->latency ());
-               }
+       if (playback) {
+               /* reverse the list so that we work backwards from the last route to run to the first */
+               RouteList* rl = routes.reader().get();
+               r.reset (new RouteList (*rl));
+               reverse (r->begin(), r->end());
        }
 
        for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
-               if (!(*i)->active()) { continue ; }
-               (*i)->set_latency_compensation (_worst_track_out_latency - (*i)->output ()->latency ());
+               samplecnt_t latency = (*i)->set_private_port_latencies (playback);
+               (*i)->set_public_port_latencies (latency, playback);
        }
-}
-
-void
-Session::post_capture_latency ()
-{
-       set_worst_capture_latency ();
-
-       /* reflect any changes in capture latencies into capture offsets
-        */
 
-       boost::shared_ptr<RouteList> rl = routes.reader();
-       for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
-               boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
-               if (tr) {
-                       tr->update_latency_information ();
-               }
+       if (playback) {
+               set_worst_output_latency ();
+               update_route_latency (true, true);
+       } else {
+               set_worst_input_latency ();
+               update_route_latency (false, false);
        }
+
+       DEBUG_TRACE (DEBUG::Latency, "JACK latency callback: DONE\n");
 }
 
 void
@@ -6972,12 +6866,12 @@ Session::initialize_latencies ()
 void
 Session::set_worst_io_latencies ()
 {
-       set_worst_playback_latency ();
-       set_worst_capture_latency ();
+       set_worst_output_latency ();
+       set_worst_input_latency ();
 }
 
 void
-Session::set_worst_playback_latency ()
+Session::set_worst_output_latency ()
 {
        if (_state_of_the_state & (InitialConnecting|Deletion)) {
                return;
@@ -6995,11 +6889,13 @@ Session::set_worst_playback_latency ()
                _worst_output_latency = max (_worst_output_latency, (*i)->output()->latency());
        }
 
+       _worst_output_latency = max (_worst_output_latency, _click_io->latency());
+
        DEBUG_TRACE (DEBUG::Latency, string_compose ("Worst output latency: %1\n", _worst_output_latency));
 }
 
 void
-Session::set_worst_capture_latency ()
+Session::set_worst_input_latency ()
 {
        if (_state_of_the_state & (InitialConnecting|Deletion)) {
                return;
@@ -7017,51 +6913,29 @@ Session::set_worst_capture_latency ()
                _worst_input_latency = max (_worst_input_latency, (*i)->input()->latency());
        }
 
-        DEBUG_TRACE (DEBUG::Latency, string_compose ("Worst input latency: %1\n", _worst_input_latency));
+       DEBUG_TRACE (DEBUG::Latency, string_compose ("Worst input latency: %1\n", _worst_input_latency));
 }
 
 void
 Session::update_latency_compensation (bool force_whole_graph)
 {
-       bool some_track_latency_changed = false;
-
        if (_state_of_the_state & (InitialConnecting|Deletion)) {
                return;
        }
 
-       DEBUG_TRACE(DEBUG::Latency, "---------------------------- update latency compensation\n\n");
-
-       _worst_track_latency = 0;
-
-       boost::shared_ptr<RouteList> r = routes.reader ();
-
-       for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
-               assert (!(*i)->is_auditioner()); // XXX remove me
-               if ((*i)->active()) {
-                       samplecnt_t tl;
-                       if ((*i)->signal_latency () != (tl = (*i)->update_signal_latency ())) {
-                               some_track_latency_changed = true;
-                       }
-                       _worst_track_latency = max (tl, _worst_track_latency);
-               }
-       }
-
-       DEBUG_TRACE (DEBUG::Latency, string_compose ("worst signal processing latency: %1 (changed ? %2)\n", _worst_track_latency,
-                                                    (some_track_latency_changed ? "yes" : "no")));
-
-       DEBUG_TRACE(DEBUG::Latency, "---------------------------- DONE update latency compensation\n\n");
+       bool some_track_latency_changed = update_route_latency (false, false);
 
        if (some_track_latency_changed || force_whole_graph)  {
                _engine.update_latencies ();
-       }
-
-
-       for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
-               boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
-               if (!tr) {
-                       continue;
+               /* above call will ask the backend up update its latencies, which
+                * eventually will trigger  AudioEngine::latency_callback () and
+                * call Session::update_latency ()
+                */
+       } else {
+               boost::shared_ptr<RouteList> r = routes.reader ();
+               for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
+                       (*i)->apply_latency_compensation ();
                }
-               tr->update_latency_information ();
        }
 }
 
@@ -7103,39 +6977,12 @@ Session::operation_in_progress (GQuark op) const
        return (find (_current_trans_quarks.begin(), _current_trans_quarks.end(), op) != _current_trans_quarks.end());
 }
 
-boost::shared_ptr<Port>
-Session::ltc_input_port () const
-{
-       assert (_ltc_input);
-       return _ltc_input->nth (0);
-}
-
 boost::shared_ptr<Port>
 Session::ltc_output_port () const
 {
        return _ltc_output ? _ltc_output->nth (0) : boost::shared_ptr<Port> ();
 }
 
-void
-Session::reconnect_ltc_input ()
-{
-       if (_ltc_input) {
-
-               string src = Config->get_ltc_source_port();
-
-               _ltc_input->disconnect (this);
-
-               if (src != _("None") && !src.empty())  {
-                       _ltc_input->nth (0)->connect (src);
-               }
-
-               if ( ARDOUR::Profile->get_trx () ) {
-                       // Tracks need this signal to update timecode_source_dropdown
-                       MtcOrLtcInputPortChanged (); //emit signal
-               }
-       }
-}
-
 void
 Session::reconnect_ltc_output ()
 {
@@ -7394,12 +7241,12 @@ Session::auto_connect_thread_run ()
                        /* this is only used for updating plugin latencies, the
                         * graph does not change. so it's safe in general.
                         * BUT..
-                        * .. update_latency_compensation () entails Track::update_latency_information()
-                        * which calls DiskWriter::set_capture_offset () which
-                        * modifies the capture offset... which can be a proplem
-                        * in "prepare_to_stop"
+                        * update_latency_compensation ()
+                        * calls DiskWriter::set_capture_offset () which
+                        * modifies the capture-offset, which can be a problem.
                         */
                        while (g_atomic_int_and (&_latency_recompute_pending, 0)) {
+                               Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
                                update_latency_compensation ();
                        }
                }