Session::request_transport_speed (double speed, bool as_default)
{
SessionEvent* ev = new SessionEvent (SessionEvent::SetTransportSpeed, SessionEvent::Add, SessionEvent::Immediate, 0, speed);
- ev->third_yes_or_no = true; // as_default
+ ev->third_yes_or_no = as_default; // as_default
DEBUG_TRACE (DEBUG::Transport, string_compose ("Request transport speed = %1 as default = %2\n", speed, as_default));
queue_event (ev);
}
void
Session::request_play_loop (bool yn, bool change_transport_roll)
{
+ if (_slave && yn) {
+ // don't attempt to loop when not using Internal Transport
+ // see also gtk2_ardour/ardour_ui_options.cc parameter_changed()
+ return;
+ }
+
SessionEvent* ev;
Location *location = _locations->auto_loop_location();
double target_speed;
for (RouteList::iterator i = r->begin (); i != r->end(); ++i) {
(*i)->realtime_handle_transport_stopped ();
}
-
+
DEBUG_TRACE (DEBUG::Transport, string_compose ("stop complete, auto-return scheduled for return to %1\n", _requested_return_frame));
/* the duration change is not guaranteed to have happened, but is likely */
-
+
todo = PostTransportWork (todo | PostTransportDuration);
if (abort) {
if (clear_state && !Config->get_loop_is_mode()) {
unset_play_loop ();
}
-
+
reset_slave_state ();
_transport_speed = 0;
PostTransportWork ptw;
boost::shared_ptr<RouteList> r = routes.reader ();
uint64_t before;
-
+
int on_entry = g_atomic_int_get (&_butler->should_do_transport_work);
finished = true;
ptw = post_transport_work();
if (get_play_loop() && !Config->get_seamless_loop()) {
DEBUG_TRACE (DEBUG::Butler, "flush loop recording fragment to disk\n");
-
+
/* this locate might be happening while we are
* loop recording.
*
} 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) {
(*i)->non_realtime_locate (_transport_frame);
// Next stop will put us where we need to be.
return false;
}
-
+
/* Note that the order of checking each AutoReturnTarget flag defines
the priority each flag.
Region Selection
Last Locate
*/
-
+
if (autoreturn & RangeSelectionStart) {
if (!_range_selection.empty()) {
jump_to = _range_selection.from;
}
}
}
-
+
if (jump_to < 0 && (autoreturn & Loop) && get_play_loop()) {
/* don't try to handle loop play when synced to JACK */
-
+
if (!synced_to_engine()) {
Location *location = _locations->auto_loop_location();
-
+
if (location) {
jump_to = location->start();
}
}
}
-
+
if (jump_to < 0 && (autoreturn & RegionSelectionStart)) {
if (!_object_selection.empty()) {
jump_to = _object_selection.from;
if (jump_to < 0 && (autoreturn & LastLocate)) {
jump_to = _last_roll_location;
}
-
+
return jump_to >= 0;
}
#else
bool
Session::select_playhead_priority_target (framepos_t& jump_to)
{
- if (!config.get_auto_return()) {
+ if (config.get_external_sync() || !config.get_auto_return()) {
return false;
}
if (_engine.connected() && !_engine.freewheeling()) {
// need to queue this in the next RT cycle
_send_timecode_update = true;
-
+
if (!dynamic_cast<MTC_Slave*>(_slave)) {
send_immediate_mmc (MIDI::MachineControlCommand (MIDI::MachineControl::cmdStop));
/* This (::non_realtime_stop()) gets called by main
process thread, which will lead to confusion
when calling AsyncMIDIPort::write().
-
+
Something must be done. XXX
*/
send_mmc_locate (_transport_frame);
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);
play_loop = true;
have_looped = false;
-
+
if (loc) {
unset_play_range ();
Session::locate (framepos_t target_frame, bool with_roll, bool with_flush, bool for_loop_enabled, bool force, bool with_mmc)
{
bool need_butler = false;
-
+
/* 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
DEBUG_TRACE (DEBUG::Transport, string_compose ("rt-locate to %1, roll %2 flush %3 loop-enabled %4 force %5 mmc %6\n",
target_frame, with_roll, with_flush, for_loop_enabled, force, with_mmc));
-
+
if (!force && _transport_frame == target_frame && !loop_changing && !for_loop_enabled) {
/* already at the desired position. Not forced to locate,
*/
bool transport_was_stopped = !transport_rolling();
-
+
if (!transport_was_stopped && (!auto_play_legal || !config.get_auto_play()) && !with_roll && !(synced_to_engine() && play_loop) &&
(!Profile->get_trx() || !(config.get_external_sync() && !synced_to_engine()))) {
realtime_stop (false, true); // XXX paul - check if the 2nd arg is really correct
add_post_transport_work (todo);
need_butler = true;
-
+
} else {
/* this is functionally what clear_clicks() does but with a tentative lock */
// 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 {
}
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);
if (Config->get_monitoring_model() == HardwareMonitoring) {
set_track_monitor_input_status (true);
}
-
+
if (synced_to_engine ()) {
if (clear_state) {
/* do this here because our response to the slave won't
}
} else if (transport_stopped() && speed == 1.0) {
-
+ if (as_default) {
+ _default_transport_speed = speed;
+ }
/* we are stopped and we want to start rolling at speed 1 */
if (Config->get_loop_is_mode() && play_loop) {
Location *location = _locations->auto_loop_location();
-
+
if (location != 0) {
if (_transport_frame != location->start()) {
}
DEBUG_TRACE (DEBUG::Transport, string_compose ("stop_transport, declick required? %1\n", get_transport_declick_required()));
-
+
if (!get_transport_declick_required()) {
/* stop has not yet been scheduled */
}
SubState new_bits;
-
+
if (actively_recording() && /* we are recording */
worst_input_latency() > current_block_size) { /* input latency exceeds block size, so simple 1 cycle delay before stop is not enough */
-
+
/* we need to capture the audio that is still somewhere in the pipeline between
wherever it was generated and the process callback. This means that even though
the user (or something else) has asked us to stop, we have to roll
we still need playback to "stop" now, however, which is why we schedule
a declick below.
*/
-
+
DEBUG_TRACE (DEBUG::Transport, string_compose ("stop transport requested @ %1, scheduled for + %2 = %3, abort = %4\n",
_transport_frame, _worst_input_latency,
_transport_frame + _worst_input_latency,
abort));
-
+
SessionEvent *ev = new SessionEvent (SessionEvent::StopOnce, SessionEvent::Replace,
_transport_frame + _worst_input_latency,
0, 0, abort);
-
+
merge_event (ev);
/* request a declick at the start of the next process cycle() so that playback ceases.
does not stop the transport too early.
*/
new_bits = SubState (PendingDeclickOut|StopPendingCapture);
-
+
} else {
-
+
/* Not recording, schedule a declick in the next process() cycle and then stop at its end */
-
+
new_bits = PendingDeclickOut;
DEBUG_TRACE (DEBUG::Transport, string_compose ("stop scheduled for next process cycle @ %1\n", _transport_frame));
}
-
+
/* we'll be called again after the declick */
transport_sub_state = SubState (transport_sub_state|new_bits);
pending_abort = abort;
} else {
DEBUG_TRACE (DEBUG::Transport, "time to actually stop\n");
-
+
/* declick was scheduled, but we've been called again, which means it is really time to stop
-
+
XXX: we should probably split this off into its own method and call it explicitly.
*/
}
DEBUG_TRACE (DEBUG::Slave, string_compose ("set new slave to %1\n", _slave));
-
+
// need to queue this for next process() cycle
_send_timecode_update = true;