X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fardour%2Fsession_transport.cc;h=de94db6f07cd853cdd1c9145516ce1623e16bf42;hb=6be56d78b199452e5dba726f2d7aaab2777d2b49;hp=aab27fe68b6435d6b2755867fed9d4c3166f118f;hpb=061a85191c301ac18f2e8ca59d43127a4499ba96;p=ardour.git diff --git a/libs/ardour/session_transport.cc b/libs/ardour/session_transport.cc index aab27fe68b..de94db6f07 100644 --- a/libs/ardour/session_transport.cc +++ b/libs/ardour/session_transport.cc @@ -30,6 +30,7 @@ #include "midi++/mmc.h" #include "midi++/port.h" +#include "midi++/manager.h" #include "ardour/ardour.h" #include "ardour/audioengine.h" @@ -39,6 +40,7 @@ #include "ardour/location.h" #include "ardour/session.h" #include "ardour/slave.h" +#include "ardour/operations.h" #include "i18n.h" @@ -122,7 +124,7 @@ Session::request_stop (bool abort, bool clear_state) } 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)); @@ -130,7 +132,7 @@ Session::request_locate (nframes_t target_frame, bool with_roll) } 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)); @@ -141,7 +143,7 @@ void 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") @@ -181,17 +183,20 @@ Session::realtime_stop (bool abort, bool clear_state) /* 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 { todo = PostTransportWork (todo | PostTransportStop); } + /* call routes */ + + boost::shared_ptr r = routes.reader (); + + for (RouteList::iterator i = r->begin (); i != r->end(); ++i) { + (*i)->realtime_handle_transport_stopped (); + } + if (actively_recording()) { /* move the transport position back to where the @@ -237,11 +242,14 @@ Session::realtime_stop (bool abort, bool clear_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 @@ -257,7 +265,28 @@ Session::butler_transport_work () 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 tr = boost::dynamic_pointer_cast (*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 tr = boost::dynamic_pointer_cast (*i); + if (tr) { + tr->adjust_capture_buffering (); + } + } + } + if (ptw & PostTransportCurveRealloc) { for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { (*i)->curve_reallocate(); @@ -407,41 +436,18 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished) reset_rf_scale (0); if (did_record) { - begin_reversible_command ("capture"); - - Location* loc = _locations.session_range_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 */ - - change_end = true; - } - - if (change_end) { - XMLNode &before = loc->get_state(); - loc->set_end(_transport_frame); - XMLNode &after = loc->get_state(); - add_command (new MementoCommand(*loc, &before, &after)); - } - - config.set_end_marker_is_free (false); + begin_reversible_command (Operations::capture); _have_captured = true; } DEBUG_TRACE (DEBUG::Transport, X_("Butler PTW: DS stop\n")); + + 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); + } + for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) { boost::shared_ptr tr = boost::dynamic_pointer_cast (*i); if (tr) { @@ -449,6 +455,10 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished) } } + if (abort && did_record) { + _state_of_the_state = StateOfTheState (_state_of_the_state & ~InCleanup); + } + boost::shared_ptr r = routes.reader (); for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { @@ -502,7 +512,7 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished) if (!synced_to_jack()) { - Location *location = _locations.auto_loop_location(); + Location *location = _locations->auto_loop_location(); if (location != 0) { _transport_frame = location->start(); @@ -567,9 +577,12 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished) 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); + + if (!dynamic_cast(_slave)) { + 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 */ @@ -587,18 +600,12 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished) 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 */ @@ -656,13 +663,11 @@ Session::set_play_loop (bool yn) 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) @@ -729,12 +734,12 @@ Session::flush_all_inserts () } 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); @@ -758,7 +763,7 @@ Session::start_locate (nframes64_t target_frame, bool with_roll, bool with_flush } int -Session::micro_locate (nframes_t distance) +Session::micro_locate (framecnt_t distance) { boost::shared_ptr rl = routes.reader(); for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) { @@ -779,8 +784,9 @@ Session::micro_locate (nframes_t 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; @@ -791,6 +797,7 @@ Session::locate (nframes64_t target_frame, bool with_roll, bool with_flush, bool set_transport_speed (1.0, false); } loop_changing = false; + Located (); /* EMIT SIGNAL */ return; } @@ -874,7 +881,7 @@ Session::locate (nframes64_t target_frame, bool with_roll, bool with_flush, bool /* 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 @@ -902,6 +909,10 @@ Session::locate (nframes64_t target_frame, bool with_roll, bool with_flush, bool _send_timecode_update = true; + if (with_mmc) { + send_mmc_locate (_transport_frame); + } + Located (); /* EMIT SIGNAL */ } @@ -937,6 +948,7 @@ Session::set_transport_speed (double speed, bool abort, bool clear_state) if (Config->get_monitoring_model() == HardwareMonitoring) { 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->record_enabled ()) { @@ -958,6 +970,8 @@ Session::set_transport_speed (double speed, bool abort, bool clear_state) } else { stop_transport (abort); } + + unset_play_loop (); } else if (transport_stopped() && speed == 1.0) { @@ -1012,6 +1026,7 @@ Session::set_transport_speed (double speed, bool abort, bool clear_state) 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; @@ -1022,7 +1037,6 @@ Session::set_transport_speed (double speed, bool abort, bool clear_state) boost::shared_ptr tr = boost::dynamic_pointer_cast (*i); if (tr && tr->realtime_set_speed (tr->speed(), true)) { todo = PostTransportWork (todo | PostTransportSpeed); - break; } } @@ -1097,6 +1111,8 @@ void 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 @@ -1131,9 +1147,14 @@ Session::start_transport () 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); + if (!dynamic_cast(_slave)) { + MIDI::Manager::instance()->mmc()->send (MIDI::MachineControlCommand (MIDI::MachineControl::cmdDeferredPlay)); + } TransportStateChange (); /* EMIT SIGNAL */ } @@ -1177,7 +1198,7 @@ Session::post_transport () } void -Session::reset_rf_scale (nframes_t motion) +Session::reset_rf_scale (framecnt_t motion) { cumulative_rf_motion += motion; @@ -1246,17 +1267,11 @@ Session::switch_to_sync_source (SyncSource src) 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; @@ -1266,17 +1281,11 @@ Session::switch_to_sync_source (SyncSource src) 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; @@ -1286,6 +1295,10 @@ Session::switch_to_sync_source (SyncSource src) return; } + if (config.get_video_pullup() != 0.0f) { + return; + } + new_slave = new JACK_Slave (_engine.jack()); break; @@ -1362,7 +1375,7 @@ Session::set_play_range (list& range, bool leave_rolling) /* 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; @@ -1401,7 +1414,7 @@ Session::set_play_range (list& range, bool leave_rolling) } 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 lar; @@ -1410,7 +1423,7 @@ Session::request_bounded_roll (nframes_t start, nframes_t end) 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; @@ -1444,9 +1457,7 @@ Session::engine_halted () 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()) { @@ -1492,11 +1503,11 @@ Session::update_latency_compensation (bool with_stop, bool abort) for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { if (with_stop) { - (*i)->handle_transport_stopped (abort, (ptw & PostTransportLocate), (!(ptw & PostTransportLocate) || pending_locate_flush)); + (*i)->nonrealtime_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 (); @@ -1552,7 +1563,7 @@ Session::reset_jack_connection (jack_client_t* jack) } 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 ()) { @@ -1564,3 +1575,35 @@ Session::maybe_stop (nframes_t limit) } 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; +}