diff options
-rw-r--r-- | libs/ardour/session_transport.cc | 77 |
1 files changed, 68 insertions, 9 deletions
diff --git a/libs/ardour/session_transport.cc b/libs/ardour/session_transport.cc index 2ed6279936..fa1c0c31d0 100644 --- a/libs/ardour/session_transport.cc +++ b/libs/ardour/session_transport.cc @@ -449,14 +449,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<RouteList> rl = routes.reader(); for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) { @@ -765,6 +784,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 @@ -775,9 +800,9 @@ Session::set_track_loop (bool yn) if (!loc) { yn = false; } - - // set all tracks to NOT use internal looping + 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->hidden()) { @@ -809,16 +834,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); } @@ -947,6 +979,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; } @@ -993,7 +1028,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; @@ -1011,7 +1046,6 @@ Session::locate (framepos_t target_frame, bool with_roll, bool with_flush, bool } add_post_transport_work (todo); - _butler->schedule_transport_work (); } else { @@ -1051,10 +1085,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()) { @@ -1063,6 +1105,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<RouteList> rl = routes.reader(); @@ -1083,6 +1137,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; @@ -1172,11 +1228,14 @@ Session::set_transport_speed (double speed, framepos_t destination_frame, bool a if (location != 0) { if (_transport_frame != location->start()) { + 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; } |