#include "midi++/mmc.h"
#include "midi++/port.h"
+#include "midi++/manager.h"
#include "ardour/ardour.h"
-#include "ardour/audio_diskstream.h"
#include "ardour/audioengine.h"
#include "ardour/auditioner.h"
#include "ardour/butler.h"
}
void
-Session::request_diskstream_speed (Diskstream& ds, double speed)
+Session::request_track_speed (Track* tr, double speed)
{
- SessionEvent* ev = new SessionEvent (SessionEvent::SetDiskstreamSpeed, SessionEvent::Add, SessionEvent::Immediate, 0, speed);
- ev->set_ptr (&ds);
+ SessionEvent* ev = new SessionEvent (SessionEvent::SetTrackSpeed, SessionEvent::Add, SessionEvent::Immediate, 0, speed);
+ ev->set_ptr (tr);
queue_event (ev);
}
}
void
-Session::request_locate (nframes_t target_frame, bool with_roll)
+Session::request_locate (framepos_t target_frame, bool with_roll)
{
SessionEvent *ev = new SessionEvent (with_roll ? SessionEvent::LocateRoll : SessionEvent::Locate, SessionEvent::Add, SessionEvent::Immediate, target_frame, 0, false);
DEBUG_TRACE (DEBUG::Transport, string_compose ("Request locate to %1\n", target_frame));
}
void
-Session::force_locate (nframes64_t target_frame, bool with_roll)
+Session::force_locate (framepos_t target_frame, bool with_roll)
{
SessionEvent *ev = new SessionEvent (with_roll ? SessionEvent::LocateRoll : SessionEvent::Locate, SessionEvent::Add, SessionEvent::Immediate, target_frame, 0, true);
DEBUG_TRACE (DEBUG::Transport, string_compose ("Request forced locate to %1\n", target_frame));
Session::request_play_loop (bool yn, bool leave_rolling)
{
SessionEvent* ev;
- Location *location = _locations.auto_loop_location();
+ Location *location = _locations->auto_loop_location();
if (location == 0 && yn) {
error << _("Cannot loop - no loop range defined")
queue_event (ev);
if (!leave_rolling && !yn && Config->get_seamless_loop() && transport_rolling()) {
- // request an immediate locate to refresh the diskstreams
+ // request an immediate locate to refresh the tracks
// after disabling looping
request_locate (_transport_frame-1, false);
}
/* assume that when we start, we'll be moving forwards */
- // FIXME: where should this really be? [DR]
- //send_full_time_code();
- deliver_mmc (MIDI::MachineControl::cmdStop, 0);
- deliver_mmc (MIDI::MachineControl::cmdLocate, _transport_frame);
-
if (_transport_speed < 0.0f) {
todo = (PostTransportWork (todo | PostTransportStop | PostTransportReverse));
} else {
/* move the transport position back to where the
request for a stop was noticed. we rolled
- past that point to pick up delayed input.
+ past that point to pick up delayed input (and/or to delick)
*/
- decrement_transport_position (_worst_output_latency);
+ if (_worst_output_latency > current_block_size) {
+ /* we rolled past the stop point to pick up data that had
+ not yet arrived. move back to where the stop occured.
+ */
+ decrement_transport_position (current_block_size + (_worst_output_latency - current_block_size));
+ } else {
+ decrement_transport_position (current_block_size);
+ }
/* the duration change is not guaranteed to have happened, but is likely */
_clear_event_type (SessionEvent::RangeStop);
_clear_event_type (SessionEvent::RangeLocate);
- disable_record (true);
-
+ /* if we're going to clear loop state, then force disabling record BUT only if we're not doing latched rec-enable */
+ disable_record (true, (!Config->get_latched_record_enable() && clear_state));
+
reset_slave_state ();
_transport_speed = 0;
_target_transport_speed = 0;
+ g_atomic_int_set (&_playback_load, 100);
+ g_atomic_int_set (&_capture_load, 100);
+
if (config.get_use_video_sync()) {
waiting_for_sync_offset = true;
}
- transport_sub_state = ((!config.get_external_sync()&& config.get_auto_return()) ? AutoReturning : 0);
+ transport_sub_state = 0;
}
void
bool finished;
PostTransportWork ptw;
boost::shared_ptr<RouteList> r = routes.reader ();
- boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
int on_entry = g_atomic_int_get (&_butler->should_do_transport_work);
finished = true;
ptw = post_transport_work();
DEBUG_TRACE (DEBUG::Transport, string_compose ("Butler transport work, todo = %1\n", enum_2_string (ptw)));
-
+
+ if (ptw & PostTransportAdjustPlaybackBuffering) {
+ for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
+ boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
+ if (tr) {
+ tr->adjust_playback_buffering ();
+ /* and refill those buffers ... */
+ tr->non_realtime_locate (_transport_frame);
+ }
+ }
+
+ }
+
+ if (ptw & PostTransportAdjustCaptureBuffering) {
+ for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
+ boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
+ if (tr) {
+ tr->adjust_capture_buffering ();
+ }
+ }
+ }
+
if (ptw & PostTransportCurveRealloc) {
for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
(*i)->curve_reallocate();
}
if (ptw & PostTransportInputChange) {
- for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
- (*i)->non_realtime_input_change ();
+ for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
+ boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
+ if (tr) {
+ tr->non_realtime_input_change ();
+ }
}
}
if (!(ptw & PostTransportLocate)) {
- for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
- if (!(*i)->hidden()) {
- (*i)->non_realtime_locate (_transport_frame);
+ for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
+ boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
+ if (tr && !tr->hidden()) {
+ tr->non_realtime_locate (_transport_frame);
}
if (on_entry != g_atomic_int_get (&_butler->should_do_transport_work)) {
/* new request, stop seeking, and start again */
}
g_atomic_int_dec_and_test (&_butler->should_do_transport_work);
+
+ DEBUG_TRACE (DEBUG::Transport, X_("Butler transport work all done\n"));
}
void
Session::non_realtime_set_speed ()
{
- boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
-
- for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
- (*i)->non_realtime_set_speed ();
+ 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->non_realtime_set_speed ();
+ }
}
}
void
Session::non_realtime_overwrite (int on_entry, bool& finished)
{
- boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
-
- for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
- if ((*i)->pending_overwrite) {
- (*i)->overwrite_existing_buffers ();
+ 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->pending_overwrite ()) {
+ tr->overwrite_existing_buffers ();
}
if (on_entry != g_atomic_int_get (&_butler->should_do_transport_work)) {
finished = false;
void
Session::non_realtime_locate ()
{
- boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
-
- for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
- (*i)->non_realtime_locate (_transport_frame);
+ 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->non_realtime_locate (_transport_frame);
+ }
}
}
did_record = false;
saved = false;
- boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
-
- for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
- if ((*i)->get_captured_frames () != 0) {
+ 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->get_captured_frames () != 0) {
did_record = true;
break;
}
if (did_record) {
begin_reversible_command ("capture");
+ _have_captured = true;
+ }
- Location* loc = _locations.end_location();
- bool change_end = false;
-
- if (_transport_frame < loc->end()) {
-
- /* stopped recording before current end */
-
- if (config.get_end_marker_is_free()) {
-
- /* first capture for this session, move end back to where we are */
-
- change_end = true;
- }
-
- } else if (_transport_frame > loc->end()) {
-
- /* stopped recording after the current end, extend it */
+ DEBUG_TRACE (DEBUG::Transport, X_("Butler PTW: DS stop\n"));
- change_end = true;
- }
+ if (abort && did_record) {
+ /* no reason to save the session file when we remove sources
+ */
+ _state_of_the_state = StateOfTheState (_state_of_the_state|InCleanup);
+ }
- if (change_end) {
- XMLNode &before = loc->get_state();
- loc->set_end(_transport_frame);
- XMLNode &after = loc->get_state();
- add_command (new MementoCommand<Location>(*loc, &before, &after));
+ for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
+ boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
+ if (tr) {
+ tr->transport_stopped_wallclock (*now, xnow, abort);
}
-
- config.set_end_marker_is_free (false);
- _have_captured = true;
}
- for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
- (*i)->transport_stopped (*now, xnow, abort);
- }
+ if (abort && did_record) {
+ _state_of_the_state = StateOfTheState (_state_of_the_state & ~InCleanup);
+ }
boost::shared_ptr<RouteList> r = routes.reader ();
if ((auto_return_enabled || synced_to_jack() || _requested_return_frame >= 0) &&
!(ptw & PostTransportLocate)) {
- /* no explicit locate queued */
+ /* no explicit locate queued */
bool do_locate = false;
if (!synced_to_jack()) {
- Location *location = _locations.auto_loop_location();
+ Location *location = _locations->auto_loop_location();
if (location != 0) {
_transport_frame = location->start();
}
- /* do this before seeking, because otherwise the Diskstreams will do the wrong thing in seamless loop mode.
+ /* do this before seeking, because otherwise the tracks will do the wrong thing in seamless loop mode.
*/
if (ptw & PostTransportClearSubstate) {
/* this for() block can be put inside the previous if() and has the effect of ... ??? what */
-
- for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
- if (!(*i)->hidden()) {
- (*i)->non_realtime_locate (_transport_frame);
+ DEBUG_TRACE (DEBUG::Transport, X_("Butler PTW: locate\n"));
+ for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
+ DEBUG_TRACE (DEBUG::Transport, string_compose ("Butler PTW: locate on %1\n", (*i)->name()));
+ boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
+ if (tr && !tr->hidden()) {
+ tr->non_realtime_locate (_transport_frame);
}
+
if (on_entry != g_atomic_int_get (&_butler->should_do_transport_work)) {
finished = false;
/* we will be back */
have_looped = false;
- send_full_time_code (0);
- deliver_mmc (MIDI::MachineControl::cmdStop, 0);
- deliver_mmc (MIDI::MachineControl::cmdLocate, _transport_frame);
+ send_full_time_code (_transport_frame);
+ MIDI::Manager::instance()->mmc()->send (MIDI::MachineControlCommand (MIDI::MachineControl::cmdStop));
+ send_mmc_locate (_transport_frame);
if ((ptw & PostTransportLocate) && get_record_enabled()) {
/* capture start has been changed, so save pending state */
save_state (_current_snapshot_name);
}
- if (ptw & PostTransportDuration) {
- DurationChanged (); /* EMIT SIGNAL */
- }
-
if (ptw & PostTransportStop) {
_play_range = false;
play_loop = false;
}
- // can't cast away volatile so copy and emit that
- nframes64_t tframe = _transport_frame;
- PositionChanged (tframe); /* EMIT SIGNAL */
+ PositionChanged (_transport_frame); /* EMIT SIGNAL */
TransportStateChange (); /* EMIT SIGNAL */
/* and start it up again if relevant */
play_loop = false;
clear_events (SessionEvent::AutoLoop);
- // set all diskstreams to NOT use internal looping
- boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
- for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
- if (!(*i)->hidden()) {
- (*i)->set_loop (0);
+ // 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()) {
+ tr->set_loop (0);
}
}
}
Location *loc;
- if (yn == play_loop || (actively_recording() && yn) || (loc = _locations.auto_loop_location()) == 0) {
+ if (yn == play_loop || (actively_recording() && yn) || (loc = _locations->auto_loop_location()) == 0) {
/* nothing to do, or can't change loop status while recording */
return;
}
- set_dirty();
-
if (yn && Config->get_seamless_loop() && synced_to_jack()) {
warning << string_compose (_("Seamless looping cannot be supported while %1 is using JACK transport.\n"
"Recommend changing the configured options"), PROGRAM_NAME)
unset_play_range ();
if (Config->get_seamless_loop()) {
- // set all diskstreams to use internal looping
- boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
- for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
- if (!(*i)->hidden()) {
- (*i)->set_loop (loc);
+ // set all tracks to 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()) {
+ tr->set_loop (loc);
}
}
}
else {
- // set all diskstreams to NOT use internal looping
- boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
- for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
- if (!(*i)->hidden()) {
- (*i)->set_loop (0);
+ // 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()) {
+ tr->set_loop (0);
}
}
}
}
void
-Session::start_locate (nframes64_t target_frame, bool with_roll, bool with_flush, bool with_loop, bool force)
+Session::start_locate (framepos_t target_frame, bool with_roll, bool with_flush, bool with_loop, bool force)
{
if (synced_to_jack()) {
double sp;
- nframes64_t pos;
+ framepos_t pos;
_slave->speed_and_position (sp, pos);
}
int
-Session::micro_locate (nframes_t distance)
+Session::micro_locate (framecnt_t distance)
{
- boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
-
- for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
- if (!(*i)->can_internal_playback_seek (distance)) {
+ 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->can_internal_playback_seek (distance)) {
return -1;
}
}
- for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
- (*i)->internal_playback_seek (distance);
+ for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
+ boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
+ if (tr) {
+ tr->internal_playback_seek (distance);
+ }
}
_transport_frame += distance;
return 0;
}
+/** @param with_mmc true to send a MMC locate command when the locate is done */
void
-Session::locate (nframes64_t target_frame, bool with_roll, bool with_flush, bool with_loop, bool force)
+Session::locate (framepos_t target_frame, bool with_roll, bool with_flush, bool with_loop, bool force, bool with_mmc)
{
if (actively_recording() && !with_loop) {
return;
set_transport_speed (1.0, false);
}
loop_changing = false;
+ Located (); /* EMIT SIGNAL */
return;
}
/* switch from input if we're going to roll */
if (Config->get_monitoring_model() == HardwareMonitoring) {
- boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
-
- for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
- if ((*i)->record_enabled ()) {
+ 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 ()) {
//cerr << "switching from input" << __FILE__ << __LINE__ << endl << endl;
- (*i)->monitor_input (!config.get_auto_input());
+ tr->monitor_input (!config.get_auto_input());
}
}
}
} else {
/* otherwise we're going to stop, so do the opposite */
if (Config->get_monitoring_model() == HardwareMonitoring) {
- boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
- for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
- if ((*i)->record_enabled ()) {
+ 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 ()) {
//cerr << "switching to input" << __FILE__ << __LINE__ << endl << endl;
- (*i)->monitor_input (true);
+ tr->monitor_input (true);
}
}
}
/* cancel looped playback if transport pos outside of loop range */
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())) {
// cancel looping directly, this is called from event handling context
if (with_loop) {
// this is only necessary for seamless looping
- boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
-
- for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
- if ((*i)->record_enabled ()) {
+ 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
- (*i)->transport_looped(_transport_frame);
+ tr->transport_looped(_transport_frame);
}
}
}
_send_timecode_update = true;
+ if (with_mmc) {
+ send_mmc_locate (_transport_frame);
+ }
+
Located (); /* EMIT SIGNAL */
}
if (Config->get_monitoring_model() == HardwareMonitoring)
{
- boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
-
- for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
- if ((*i)->record_enabled ()) {
+ 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 ()) {
//cerr << "switching to input" << __FILE__ << __LINE__ << endl << endl;
- (*i)->monitor_input (true);
+ tr->monitor_input (true);
}
}
}
if (Config->get_monitoring_model() == HardwareMonitoring) {
- boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
-
- for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
- if (config.get_auto_input() && (*i)->record_enabled ()) {
+ 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 (config.get_auto_input() && tr && tr->record_enabled ()) {
//cerr << "switching from input" << __FILE__ << __LINE__ << endl << endl;
- (*i)->monitor_input (false);
+ tr->monitor_input (false);
}
}
}
if ((_transport_speed && speed * _transport_speed < 0.0) || (_last_transport_speed * speed < 0.0) || (_last_transport_speed == 0.0f && speed < 0.0f)) {
todo = PostTransportWork (todo | PostTransportReverse);
+ _last_roll_or_reversal_location = _transport_frame;
}
_last_transport_speed = _transport_speed;
_transport_speed = speed;
- boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
- for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
- if ((*i)->realtime_set_speed ((*i)->speed(), true)) {
+ 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->realtime_set_speed (tr->speed(), true)) {
todo = PostTransportWork (todo | PostTransportSpeed);
break;
}
return;
}
- if (actively_recording() && !(transport_sub_state & StopPendingCapture) &&
- _worst_output_latency > current_block_size)
- {
+ if (actively_recording() && !(transport_sub_state & StopPendingCapture) && _worst_output_latency > current_block_size) {
+
+ 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->prepare_to_stop (_transport_frame);
+ }
+ }
/* we need to capture the audio that has still not yet been received by the system
at the time the stop is requested, so we have to roll past that time.
if ((transport_sub_state & PendingDeclickOut) == 0) {
+
+ if (!(transport_sub_state & StopPendingCapture)) {
+ 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->prepare_to_stop (_transport_frame);
+ }
+ }
+ }
+
transport_sub_state |= PendingDeclickOut;
/* we'll be called again after the declick */
pending_abort = abort;
Session::start_transport ()
{
_last_roll_location = _transport_frame;
+ _last_roll_or_reversal_location = _transport_frame;
+
have_looped = false;
/* if record status is Enabled, move it to Recording. if its
_transport_speed = 1.0;
_target_transport_speed = 1.0;
- boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
- for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
- (*i)->realtime_set_speed ((*i)->speed(), true);
+ 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->realtime_set_speed (tr->speed(), true);
+ }
+ (*i)->automation_snapshot (_transport_frame, true);
}
- deliver_mmc(MIDI::MachineControl::cmdDeferredPlay, _transport_frame);
+ Timecode::Time time;
+ timecode_time_subframes (_transport_frame, time);
+ MIDI::Manager::instance()->mmc()->send (MIDI::MachineControlCommand (MIDI::MachineControl::cmdDeferredPlay));
TransportStateChange (); /* EMIT SIGNAL */
}
}
void
-Session::reset_rf_scale (nframes_t motion)
+Session::reset_rf_scale (framecnt_t motion)
{
cumulative_rf_motion += motion;
delete _slave;
_slave = new_slave;
- boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
- for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
- if (!(*i)->hidden()) {
- if ((*i)->realtime_set_speed ((*i)->speed(), true)) {
+ 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()) {
+ if (tr->realtime_set_speed (tr->speed(), true)) {
non_rt_required = true;
}
- (*i)->set_slaved (_slave != 0);
+ tr->set_slaved (_slave != 0);
}
}
return;
}
- if (_mtc_port) {
- try {
- new_slave = new MTC_Slave (*this, *_mtc_port);
- }
-
- catch (failed_constructor& err) {
- return;
- }
+ try {
+ new_slave = new MTC_Slave (*this, *MIDI::Manager::instance()->mtc_input_port());
+ }
- } else {
- error << _("No MTC port defined: MTC slaving is impossible.") << endmsg;
+ catch (failed_constructor& err) {
return;
}
break;
return;
}
- if (_midi_clock_port) {
- try {
- new_slave = new MIDIClock_Slave (*this, *_midi_clock_port, 24);
- }
-
- catch (failed_constructor& err) {
- return;
- }
-
- } else {
- error << _("No MIDI Clock port defined: MIDI Clock slaving is impossible.") << endmsg;
+ try {
+ new_slave = new MIDIClock_Slave (*this, *MIDI::Manager::instance()->midi_clock_input_port(), 24);
+ }
+
+ catch (failed_constructor& err) {
return;
}
break;
return;
}
+ if (config.get_video_pullup() != 0.0f) {
+ return;
+ }
+
new_slave = new JACK_Slave (_engine.jack());
break;
}
void
-Session::reverse_diskstream_buffers ()
+Session::reverse_track_buffers ()
{
add_post_transport_work (PostTransportReverse);
_butler->schedule_transport_work ();
}
void
-Session::set_diskstream_speed (Diskstream* stream, double speed)
+Session::set_track_speed (Track* track, double speed)
{
- if (stream->realtime_set_speed (speed, false)) {
+ if (track->realtime_set_speed (speed, false)) {
add_post_transport_work (PostTransportSpeed);
_butler->schedule_transport_work ();
set_dirty ();
/* locating/stopping is subject to delays for declicking.
*/
- nframes_t requested_frame = (*i).end;
+ framepos_t requested_frame = i->end;
if (requested_frame > current_block_size) {
requested_frame -= current_block_size;
}
void
-Session::request_bounded_roll (nframes_t start, nframes_t end)
+Session::request_bounded_roll (framepos_t start, framepos_t end)
{
AudioRange ar (start, end, 0);
list<AudioRange> lar;
request_play_range (&lar, true);
}
void
-Session::request_roll_at_and_return (nframes_t start, nframes_t return_to)
+Session::request_roll_at_and_return (framepos_t start, framepos_t return_to)
{
SessionEvent *ev = new SessionEvent (SessionEvent::LocateRollLocate, SessionEvent::Add, SessionEvent::Immediate, return_to, 1.0);
ev->target2_frame = start;
void
Session::xrun_recovery ()
{
- // can't cast away volatile so copy and emit that
- nframes64_t tframe = _transport_frame;
- Xrun (tframe); //EMIT SIGNAL
+ Xrun (_transport_frame); //EMIT SIGNAL
if (Config->get_stop_recording_on_xrun() && actively_recording()) {
(*i)->handle_transport_stopped (abort, (ptw & PostTransportLocate), (!(ptw & PostTransportLocate) || pending_locate_flush));
}
- nframes_t old_latency = (*i)->output()->signal_latency ();
- nframes_t track_latency = (*i)->update_total_latency ();
+ framecnt_t old_latency = (*i)->output()->signal_latency ();
+ framecnt_t track_latency = (*i)->update_total_latency ();
if (old_latency != track_latency) {
(*i)->input()->update_port_total_latencies ();
/* reflect any changes in latencies into capture offsets
*/
-
- boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
-
- for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
- (*i)->set_capture_offset ();
+
+ 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->set_capture_offset ();
+ }
}
}
}
bool
-Session::maybe_stop (nframes_t limit)
+Session::maybe_stop (framepos_t limit)
{
if ((_transport_speed > 0.0f && _transport_frame >= limit) || (_transport_speed < 0.0f && _transport_frame == 0)) {
if (synced_to_jack () && config.get_jack_time_master ()) {
}
return false;
}
+
+void
+Session::send_mmc_locate (framepos_t t)
+{
+ Timecode::Time time;
+ timecode_time_subframes (t, time);
+ MIDI::Manager::instance()->mmc()->send (MIDI::MachineControlCommand (time));
+}
+
+/** Ask the transport to not send timecode until further notice. The suspension
+ * will come into effect some finite time after this call, and timecode_transmission_suspended()
+ * should be checked by the caller to find out when.
+ */
+void
+Session::request_suspend_timecode_transmission ()
+{
+ SessionEvent* ev = new SessionEvent (SessionEvent::SetTimecodeTransmission, SessionEvent::Add, SessionEvent::Immediate, 0, 0, false);
+ queue_event (ev);
+}
+
+void
+Session::request_resume_timecode_transmission ()
+{
+ SessionEvent* ev = new SessionEvent (SessionEvent::SetTimecodeTransmission, SessionEvent::Add, SessionEvent::Immediate, 0, 0, true);
+ queue_event (ev);
+}
+
+bool
+Session::timecode_transmission_suspended () const
+{
+ return g_atomic_int_get (&_suspend_timecode_transmission) == 1;
+}