fix reset of transport speed when seamless looping; add a few comments and tidy-ups to related transport code

git-svn-id: svn://localhost/ardour2/branches/3.0@12818 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
Paul Davis 2012-06-22 14:27:51 +00:00
parent d70429a066
commit 8c10320497
5 changed files with 64 additions and 34 deletions

View file

@ -648,6 +648,9 @@ ShuttleControl::parameter_changed (std::string p)
if (_session->transport_speed() == 1.0) { if (_session->transport_speed() == 1.0) {
queue_draw (); queue_draw ();
} else { } else {
/* reset current speed and
revert to 1.0 as the default
*/
_session->request_transport_speed (1.0); _session->request_transport_speed (1.0);
/* redraw when speed changes */ /* redraw when speed changes */
} }

View file

@ -329,7 +329,7 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
void goto_start (); void goto_start ();
void use_rf_shuttle_speed (); void use_rf_shuttle_speed ();
void allow_auto_play (bool yn); void allow_auto_play (bool yn);
void request_transport_speed (double speed); void request_transport_speed (double speed);
void request_transport_speed_nonzero (double); void request_transport_speed_nonzero (double);
void request_overwrite_buffer (Track *); void request_overwrite_buffer (Track *);
void adjust_playback_buffering(); void adjust_playback_buffering();
@ -1210,7 +1210,7 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
void start_locate (framepos_t, bool with_roll, bool with_flush, bool with_loop=false, bool force=false); void start_locate (framepos_t, bool with_roll, bool with_flush, bool with_loop=false, bool force=false);
void force_locate (framepos_t frame, bool with_roll = false); void force_locate (framepos_t frame, bool with_roll = false);
void set_track_speed (Track *, double speed); void set_track_speed (Track *, double speed);
void set_transport_speed (double speed, bool abort = false, bool clear_state = false); void set_transport_speed (double speed, bool abort = false, bool clear_state = false);
void stop_transport (bool abort = false, bool clear_state = false); void stop_transport (bool abort = false, bool clear_state = false);
void start_transport (); void start_transport ();
void realtime_stop (bool abort, bool clear_state); void realtime_stop (bool abort, bool clear_state);

View file

@ -85,7 +85,7 @@ public:
boost::shared_ptr<Region> region; boost::shared_ptr<Region> region;
SessionEvent (Type t, Action a, framepos_t when, framepos_t where, double spd, bool yn = false, bool yn2 = false) SessionEvent (Type t, Action a, framepos_t when, framepos_t where, double spd, bool yn = false, bool yn2 = false)
: type (t) : type (t)
, action (a) , action (a)
, action_frame (when) , action_frame (when)

View file

@ -1015,6 +1015,9 @@ Session::process_event (SessionEvent* ev)
case SessionEvent::AutoLoop: case SessionEvent::AutoLoop:
if (play_loop) { if (play_loop) {
/* roll after locate, do not flush, set "with loop"
true only if we are seamless looping
*/
start_locate (ev->target_frame, true, false, Config->get_seamless_loop()); start_locate (ev->target_frame, true, false, Config->get_seamless_loop());
} }
remove = false; remove = false;
@ -1034,10 +1037,10 @@ Session::process_event (SessionEvent* ev)
case SessionEvent::Locate: case SessionEvent::Locate:
if (ev->yes_or_no) { if (ev->yes_or_no) {
// cerr << "forced locate to " << ev->target_frame << endl; /* args: do not roll after locate, do flush, not with loop */
locate (ev->target_frame, false, true, false); locate (ev->target_frame, false, true, false);
} else { } else {
// cerr << "soft locate to " << ev->target_frame << endl; /* args: do not roll after locate, do flush, not with loop */
start_locate (ev->target_frame, false, true, false); start_locate (ev->target_frame, false, true, false);
} }
_send_timecode_update = true; _send_timecode_update = true;
@ -1045,10 +1048,10 @@ Session::process_event (SessionEvent* ev)
case SessionEvent::LocateRoll: case SessionEvent::LocateRoll:
if (ev->yes_or_no) { if (ev->yes_or_no) {
// cerr << "forced locate to+roll " << ev->target_frame << endl; /* args: roll after locate, do flush, not with loop */
locate (ev->target_frame, true, true, false); locate (ev->target_frame, true, true, false);
} else { } else {
// cerr << "soft locate to+roll " << ev->target_frame << endl; /* args: roll after locate, do flush, not with loop */
start_locate (ev->target_frame, true, true, false); start_locate (ev->target_frame, true, true, false);
} }
_send_timecode_update = true; _send_timecode_update = true;
@ -1101,6 +1104,7 @@ Session::process_event (SessionEvent* ev)
break; break;
case SessionEvent::RangeLocate: case SessionEvent::RangeLocate:
/* args: roll after locate, do flush, not with loop */
start_locate (ev->target_frame, true, true, false); start_locate (ev->target_frame, true, true, false);
remove = false; remove = false;
del = false; del = false;

View file

@ -760,8 +760,9 @@ Session::set_play_loop (bool yn)
merge_event (new SessionEvent (SessionEvent::AutoLoopDeclick, SessionEvent::Replace, dcp, dcl, 0.0f)); merge_event (new SessionEvent (SessionEvent::AutoLoopDeclick, SessionEvent::Replace, dcp, dcl, 0.0f));
merge_event (new SessionEvent (SessionEvent::AutoLoop, SessionEvent::Replace, loc->end(), loc->start(), 0.0f)); merge_event (new SessionEvent (SessionEvent::AutoLoop, SessionEvent::Replace, loc->end(), loc->start(), 0.0f));
/* locate to start of loop and roll. If doing seamless loop, force a /* locate to start of loop and roll.
locate+buffer refill even if we are positioned there already.
args: positition, roll=true, flush=true, with_loop=false, force buffer refill if seamless looping
*/ */
start_locate (loc->start(), true, true, false, Config->get_seamless_loop()); start_locate (loc->start(), true, true, false, Config->get_seamless_loop());
@ -837,13 +838,21 @@ Session::micro_locate (framecnt_t distance)
/** @param with_mmc true to send a MMC locate command when the locate is done */ /** @param with_mmc true to send a MMC locate command when the locate is done */
void void
Session::locate (framepos_t target_frame, bool with_roll, bool with_flush, bool with_loop, bool force, bool with_mmc) Session::locate (framepos_t target_frame, bool with_roll, bool with_flush, bool for_seamless_loop, bool force, bool with_mmc)
{ {
if (actively_recording() && !with_loop) { /* Locates for seamless looping are fairly different from other
* locates. They assume that the diskstream buffers for each track
* already have the correct data in them, and thus there is no need to
* actually tell the tracks to locate. What does need to be done,
* though, is all the housekeeping that is associated with non-linear
* changes in the value of _transport_frame.
*/
if (actively_recording() && !for_seamless_loop) {
return; return;
} }
if (!force && _transport_frame == target_frame && !loop_changing && !with_loop) { if (!force && _transport_frame == target_frame && !loop_changing && !for_seamless_loop) {
if (with_roll) { if (with_roll) {
set_transport_speed (1.0, false); set_transport_speed (1.0, false);
} }
@ -852,10 +861,10 @@ Session::locate (framepos_t target_frame, bool with_roll, bool with_flush, bool
return; return;
} }
if (_transport_speed && !with_loop) { if (_transport_speed && !for_seamless_loop) {
/* Schedule a declick. We'll be called again when its done. /* Schedule a declick. We'll be called again when its done.
We only do it this way for ordinary locates, not those We only do it this way for ordinary locates, not those
due to loops. due to **seamless** loops.
*/ */
if (!(transport_sub_state & PendingDeclickOut)) { if (!(transport_sub_state & PendingDeclickOut)) {
@ -883,18 +892,21 @@ Session::locate (framepos_t target_frame, bool with_roll, bool with_flush, bool
* *
*/ */
if (transport_rolling() && (!auto_play_legal || !config.get_auto_play()) && !with_roll && !(synced_to_jack() && play_loop)) { bool transport_was_stopped = !transport_rolling();
if (transport_was_stopped && (!auto_play_legal || !config.get_auto_play()) && !with_roll && !(synced_to_jack() && play_loop)) {
realtime_stop (false, true); // XXX paul - check if the 2nd arg is really correct realtime_stop (false, true); // XXX paul - check if the 2nd arg is really correct
transport_was_stopped = true;
} else { } else {
/* otherwise tell the world that we located */ /* otherwise tell the world that we located */
realtime_locate (); realtime_locate ();
} }
if (force || !with_loop || loop_changing) { if (force || !for_seamless_loop || loop_changing) {
PostTransportWork todo = PostTransportLocate; PostTransportWork todo = PostTransportLocate;
if (with_roll) { if (with_roll && transport_was_stopped) {
todo = PostTransportWork (todo | PostTransportRoll); todo = PostTransportWork (todo | PostTransportRoll);
} }
@ -931,27 +943,39 @@ Session::locate (framepos_t target_frame, bool with_roll, bool with_flush, bool
/* cancel looped playback if transport pos outside of loop range */ /* cancel looped playback if transport pos outside of loop range */
if (play_loop) { if (play_loop) {
Location* al = _locations->auto_loop_location(); Location* al = _locations->auto_loop_location();
if (al && (_transport_frame < al->start() || _transport_frame > al->end())) { if (al) {
// cancel looping directly, this is called from event handling context if (_transport_frame < al->start() || _transport_frame > al->end()) {
set_play_loop (false);
}
else if (al && _transport_frame == al->start()) {
if (with_loop) {
// this is only necessary for seamless looping
boost::shared_ptr<RouteList> rl = routes.reader(); // located outside the loop: cancel looping directly, this is called from event handling context
for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i); set_play_loop (false);
if (tr && tr->record_enabled ()) {
// tell it we've looped, so it can deal with the record state } else if (_transport_frame == al->start()) {
tr->transport_looped(_transport_frame);
// located to start of loop - this is looping, basically
if (for_seamless_loop) {
// this is only necessary for seamless 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->record_enabled ()) {
// tell it we've looped, so it can deal with the record state
tr->transport_looped (_transport_frame);
}
} }
} }
have_looped = true;
TransportLooped(); // EMIT SIGNAL
} }
have_looped = true;
TransportLooped(); // EMIT SIGNAL
} }
} }
@ -1190,7 +1214,7 @@ Session::start_transport ()
transport_sub_state |= PendingDeclickIn; transport_sub_state |= PendingDeclickIn;
_transport_speed = 1.0; _transport_speed = 1.0;
_target_transport_speed = 1.0; _target_transport_speed = _transport_speed;
boost::shared_ptr<RouteList> rl = routes.reader(); boost::shared_ptr<RouteList> rl = routes.reader();
for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) { for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
@ -1237,7 +1261,6 @@ Session::post_transport ()
if (((!config.get_external_sync() && (auto_play_legal && config.get_auto_play())) && !_exporting) || (ptw & PostTransportRoll)) { if (((!config.get_external_sync() && (auto_play_legal && config.get_auto_play())) && !_exporting) || (ptw & PostTransportRoll)) {
start_transport (); start_transport ();
} else { } else {
transport_sub_state = 0; transport_sub_state = 0;
} }