diff --git a/libs/ardour/session_transport.cc b/libs/ardour/session_transport.cc index c27e6e356e..a1a35af7cb 100644 --- a/libs/ardour/session_transport.cc +++ b/libs/ardour/session_transport.cc @@ -452,14 +452,33 @@ Session::non_realtime_locate () DEBUG_TRACE (DEBUG::Transport, string_compose ("locate tracks to %1\n", _transport_frame)); if (Config->get_loop_is_mode() && get_play_loop()) { + Location *loc = _locations->auto_loop_location(); + if (!loc || (_transport_frame < loc->start() || _transport_frame >= loc->end())) { /* jumped out of loop range: stop tracks from looping, but leave loop (mode) enabled. */ set_track_loop (false); + + } else if (loc && Config->get_seamless_loop() && (loc->start() == _transport_frame)) { + + /* jumping to start of loop. This might have been done before but it is + * idempotent and cheap. Doing it here ensures that when we start playback + * outside the loop we still flip tracks into the magic seamless mode + * when needed. + */ + set_track_loop (true); + + } else if (loc) { + set_track_loop (false); } + + } else { + + /* no more looping .. should have been noticed elsewhere */ } + boost::shared_ptr rl = routes.reader(); for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) { @@ -816,6 +835,12 @@ Session::unset_play_loop () clear_events (SessionEvent::AutoLoop); clear_events (SessionEvent::AutoLoopDeclick); set_track_loop (false); + + if (Config->get_seamless_loop()) { + /* likely need to flush track buffers: this will locate us to wherever we are */ + add_post_transport_work (PostTransportLocate); + _butler->schedule_transport_work (); + } } void @@ -826,9 +851,9 @@ Session::set_track_loop (bool yn) if (!loc) { yn = false; } - - // set all tracks to NOT use internal looping + boost::shared_ptr rl = routes.reader (); + for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) { boost::shared_ptr tr = boost::dynamic_pointer_cast (*i); if (tr && !tr->hidden()) { @@ -860,16 +885,23 @@ Session::set_play_loop (bool yn, double speed) if (yn) { play_loop = true; - + have_looped = false; + if (loc) { unset_play_range (); if (Config->get_seamless_loop()) { - // set all tracks to use internal looping - set_track_loop (true); + if (!Config->get_loop_is_mode()) { + /* set all tracks to use internal looping */ + set_track_loop (true); + } else { + /* we will do this in the locate to the start OR when we hit the end + * of the loop for the first time + */ + } } else { - // set all tracks to NOT use internal looping + /* set all tracks to NOT use internal looping */ set_track_loop (false); } @@ -997,6 +1029,9 @@ Session::locate (framepos_t target_frame, bool with_roll, bool with_flush, bool * changes in the value of _transport_frame. */ + DEBUG_TRACE (DEBUG::Transport, string_compose ("rt-locate to %1, roll %2 flush %3 seamless %4 force %5 mmc %6\n", + target_frame, with_roll, with_flush, for_seamless_loop, force, with_mmc)); + if (actively_recording() && !for_seamless_loop) { return; } @@ -1043,7 +1078,7 @@ Session::locate (framepos_t target_frame, bool with_roll, bool with_flush, bool */ bool transport_was_stopped = !transport_rolling(); - + if (transport_was_stopped && (!auto_play_legal || !config.get_auto_play()) && !with_roll && !(synced_to_engine() && play_loop)) { realtime_stop (false, true); // XXX paul - check if the 2nd arg is really correct transport_was_stopped = true; @@ -1061,7 +1096,6 @@ Session::locate (framepos_t target_frame, bool with_roll, bool with_flush, bool } add_post_transport_work (todo); - _butler->schedule_transport_work (); } else { @@ -1101,10 +1135,18 @@ Session::locate (framepos_t target_frame, bool with_roll, bool with_flush, bool // located outside the loop: cancel looping directly, this is called from event handling context + have_looped = false; + if (!Config->get_loop_is_mode()) { set_play_loop (false, _transport_speed); } else { - /* handled in ::non_realtime_locate() */ + if (Config->get_seamless_loop()) { + /* this will make the non_realtime_locate() in the butler + which then causes seek() in tracks actually do the right + thing. + */ + set_track_loop (false); + } } } else if (_transport_frame == al->start()) { @@ -1113,6 +1155,18 @@ Session::locate (framepos_t target_frame, bool with_roll, bool with_flush, bool if (for_seamless_loop) { + if (!have_looped) { + /* first time */ + if (_last_roll_location != al->start()) { + /* didn't start at loop start - playback must have + * started before loop since we've now hit the loop + * end. + */ + add_post_transport_work (PostTransportLocate); + } + + } + // this is only necessary for seamless looping boost::shared_ptr rl = routes.reader(); @@ -1133,6 +1187,8 @@ Session::locate (framepos_t target_frame, bool with_roll, bool with_flush, bool } } + _butler->schedule_transport_work (); + loop_changing = false; _send_timecode_update = true; @@ -1222,7 +1278,14 @@ Session::set_transport_speed (double speed, framepos_t destination_frame, bool a if (location != 0) { if (_transport_frame != location->start()) { - // jump to start and then roll from there + + if (Config->get_seamless_loop()) { + /* force tracks to do their thing */ + set_track_loop (true); + } + + /* jump to start and then roll from there */ + request_locate (location->start(), true); return; }