X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fardour%2Fsession_transport.cc;h=2cd8de49bfda2354514c4eee0b2597e701582fa6;hb=21ea94c000bb30b7da111930aa4095b87f390cdd;hp=b98a044d89aa9f6c5e8000a8e5ebf7b29f492668;hpb=30968b854257cb5f9159ca59589f783c85615601;p=ardour.git diff --git a/libs/ardour/session_transport.cc b/libs/ardour/session_transport.cc index b98a044d89..2cd8de49bf 100644 --- a/libs/ardour/session_transport.cc +++ b/libs/ardour/session_transport.cc @@ -30,10 +30,10 @@ #include "pbd/enumwriter.h" #include "pbd/pthread_utils.h" #include "pbd/memento_command.h" +#include "pbd/stacktrace.h" #include "midi++/mmc.h" #include "midi++/port.h" -#include "midi++/manager.h" #include "ardour/audioengine.h" #include "ardour/auditioner.h" @@ -41,6 +41,8 @@ #include "ardour/click.h" #include "ardour/debug.h" #include "ardour/location.h" +#include "ardour/profile.h" +#include "ardour/scene_changer.h" #include "ardour/session.h" #include "ardour/slave.h" #include "ardour/operations.h" @@ -87,7 +89,7 @@ Session::request_sync_source (Slave* new_slave) seamless = Config->get_seamless_loop (); - if (dynamic_cast(new_slave)) { + if (dynamic_cast(new_slave)) { /* JACK cannot support seamless looping at present */ Config->set_seamless_loop (false); } else { @@ -159,10 +161,11 @@ Session::force_locate (framepos_t target_frame, bool with_roll) } void -Session::request_play_loop (bool yn, bool leave_rolling) +Session::request_play_loop (bool yn, bool change_transport_roll) { SessionEvent* ev; Location *location = _locations->auto_loop_location(); + double target_speed; if (location == 0 && yn) { error << _("Cannot loop - no loop range defined") @@ -170,14 +173,44 @@ Session::request_play_loop (bool yn, bool leave_rolling) return; } - ev = new SessionEvent (SessionEvent::SetLoop, SessionEvent::Add, SessionEvent::Immediate, 0, (leave_rolling ? 1.0 : 0.0), yn); - DEBUG_TRACE (DEBUG::Transport, string_compose ("Request set loop = %1, leave rolling ? %2\n", yn, leave_rolling)); + if (change_transport_roll) { + if (transport_rolling()) { + /* start looping at current speed */ + target_speed = transport_speed (); + } else { + /* currently stopped */ + if (yn) { + /* start looping at normal speed */ + target_speed = 1.0; + } else { + target_speed = 0.0; + } + } + } else { + /* leave the speed alone */ + target_speed = transport_speed (); + } + + ev = new SessionEvent (SessionEvent::SetLoop, SessionEvent::Add, SessionEvent::Immediate, 0, target_speed, yn); + DEBUG_TRACE (DEBUG::Transport, string_compose ("Request set loop = %1, change roll state ? %2\n", yn, change_transport_roll)); queue_event (ev); - if (!leave_rolling && !yn && Config->get_seamless_loop() && transport_rolling()) { - // request an immediate locate to refresh the tracks - // after disabling looping - request_locate (_transport_frame-1, false); + if (yn) { + if (!change_transport_roll) { + if (!transport_rolling()) { + /* we're not changing transport state, but we do want + to set up position for the new loop. Don't + do this if we're rolling already. + */ + request_locate (location->start(), false); + } + } + } else { + if (!change_transport_roll && Config->get_seamless_loop() && transport_rolling()) { + // request an immediate locate to refresh the tracks + // after disabling looping + request_locate (_transport_frame-1, false); + } } } @@ -194,6 +227,14 @@ Session::request_play_range (list* range, bool leave_rolling) queue_event (ev); } +void +Session::request_cancel_play_range () +{ + SessionEvent* ev = new SessionEvent (SessionEvent::CancelPlayAudioRange, SessionEvent::Add, SessionEvent::Immediate, 0, 0); + queue_event (ev); +} + + void Session::realtime_stop (bool abort, bool clear_state) { @@ -384,6 +425,7 @@ Session::butler_transport_work () g_atomic_int_dec_and_test (&_butler->should_do_transport_work); DEBUG_TRACE (DEBUG::Transport, X_("Butler transport work all done\n")); + DEBUG_TRACE (DEBUG::Transport, X_(string_compose ("Frame %1\n", _transport_frame))); } void @@ -423,6 +465,8 @@ Session::non_realtime_locate () (*i)->non_realtime_locate (_transport_frame); } + _scene_changer->locate (_transport_frame); + /* XXX: it would be nice to generate the new clicks here (in the non-RT thread) rather than clearing them so that the RT thread has to spend time constructing them (in Session::click). @@ -498,6 +542,11 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished) if (did_record) { commit_reversible_command (); + /* increase take name */ + if (config.get_track_name_take () && !config.get_take_name ().empty()) { + string newname = config.get_take_name(); + config.set_take_name(bump_name_number (newname)); + } } if (_engine.running()) { @@ -514,13 +563,13 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished) if (auto_return_enabled || (ptw & PostTransportLocate) || (_requested_return_frame >= 0) || - synced_to_jack()) { + synced_to_engine()) { if (pending_locate_flush) { flush_all_inserts (); } - if ((auto_return_enabled || synced_to_jack() || _requested_return_frame >= 0) && + if ((auto_return_enabled || synced_to_engine() || _requested_return_frame >= 0) && !(ptw & PostTransportLocate)) { /* no explicit locate queued */ @@ -531,8 +580,6 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished) /* explicit return request pre-queued in event list. overrides everything else */ - cerr << "explicit auto-return to " << _requested_return_frame << endl; - _transport_frame = _requested_return_frame; do_locate = true; @@ -543,7 +590,7 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished) /* don't try to handle loop play when synced to JACK */ - if (!synced_to_jack()) { + if (!synced_to_engine()) { Location *location = _locations->auto_loop_location(); @@ -589,8 +636,10 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished) */ if (ptw & PostTransportClearSubstate) { - _play_range = false; - unset_play_loop (); + unset_play_range (); + if (!Config->get_loop_is_mode()) { + unset_play_loop (); + } } /* this for() block can be put inside the previous if() and has the effect of ... ??? what */ @@ -609,11 +658,23 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished) have_looped = false; - if (!_engine.freewheeling()) { - send_full_time_code (_transport_frame); + /* don't bother with this stuff if we're disconnected from the engine, + because there will be no process callbacks to deliver stuff from + */ + + if (_engine.connected() && !_engine.freewheeling()) { + // need to queue this in the next RT cycle + _send_timecode_update = true; if (!dynamic_cast(_slave)) { - MIDI::Manager::instance()->mmc()->send (MIDI::MachineControlCommand (MIDI::MachineControl::cmdStop)); + _mmc->send (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); } } @@ -645,8 +706,10 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished) } if (ptw & PostTransportStop) { - _play_range = false; - play_loop = false; + unset_play_range (); + if (!Config->get_loop_is_mode()) { + unset_play_loop (); + } } PositionChanged (_transport_frame); /* EMIT SIGNAL */ @@ -711,7 +774,7 @@ Session::unset_play_loop () } void -Session::set_play_loop (bool yn) +Session::set_play_loop (bool yn, double speed) { /* Called from event-handling context */ @@ -722,7 +785,7 @@ Session::set_play_loop (bool yn) return; } - if (yn && Config->get_seamless_loop() && synced_to_jack()) { + if (yn && Config->get_seamless_loop() && synced_to_engine()) { warning << string_compose ( _("Seamless looping cannot be supported while %1 is using JACK transport.\n" "Recommend changing the configured options"), PROGRAM_NAME) @@ -770,12 +833,24 @@ Session::set_play_loop (bool yn) 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)); - /* locate to start of loop and roll. + /* if requested to roll, locate to start of loop and + * roll but ONLY if we're not already rolling. 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()); + if (Config->get_loop_is_mode()) { + /* loop IS a transport mode: if already + rolling, do not locate to loop start. + */ + if (!transport_rolling() && (speed != 0.0)) { + start_locate (loc->start(), true, true, false, Config->get_seamless_loop()); + } + } else { + if (speed != 0.0) { + start_locate (loc->start(), true, true, false, Config->get_seamless_loop()); + } + } } } else { @@ -799,7 +874,7 @@ Session::flush_all_inserts () void Session::start_locate (framepos_t target_frame, bool with_roll, bool with_flush, bool with_loop, bool force) { - if (synced_to_jack()) { + if (synced_to_engine()) { double sp; framepos_t pos; @@ -914,7 +989,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_jack() && play_loop)) { + 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; } else { @@ -971,7 +1046,9 @@ 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 - set_play_loop (false); + if (!Config->get_loop_is_mode()) { + set_play_loop (false, _transport_speed); + } } else if (_transport_frame == al->start()) { @@ -1007,6 +1084,7 @@ Session::locate (framepos_t target_frame, bool with_roll, bool with_flush, bool send_mmc_locate (_transport_frame); } + _last_roll_location = _last_roll_or_reversal_location = _transport_frame; Located (); /* EMIT SIGNAL */ } @@ -1054,7 +1132,7 @@ Session::set_transport_speed (double speed, bool abort, bool clear_state, bool a set_track_monitor_input_status (true); } - if (synced_to_jack ()) { + if (synced_to_engine ()) { if (clear_state) { /* do this here because our response to the slave won't take care of it. @@ -1067,17 +1145,32 @@ Session::set_transport_speed (double speed, bool abort, bool clear_state, bool a stop_transport (abort); } - unset_play_loop (); + if (!Config->get_loop_is_mode()) { + unset_play_loop (); + } } else if (transport_stopped() && speed == 1.0) { /* 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()) { + /* jump to start and then roll from there */ + request_locate (location->start(), true); + return; + } + } + } + if (Config->get_monitoring_model() == HardwareMonitoring && config.get_auto_input()) { set_track_monitor_input_status (false); } - if (synced_to_jack()) { + if (synced_to_engine()) { _engine.transport_start (); } else { start_transport (); @@ -1087,7 +1180,7 @@ Session::set_transport_speed (double speed, bool abort, bool clear_state, bool a /* not zero, not 1.0 ... varispeed */ - if ((synced_to_jack()) && speed != 0.0 && speed != 1.0) { + if ((synced_to_engine()) && speed != 0.0 && speed != 1.0) { warning << string_compose ( _("Global varispeed cannot be supported while %1 is connected to JACK transport control"), PROGRAM_NAME) @@ -1258,7 +1351,7 @@ Session::start_transport () Timecode::Time time; timecode_time_subframes (_transport_frame, time); if (!dynamic_cast(_slave)) { - MIDI::Manager::instance()->mmc()->send (MIDI::MachineControlCommand (MIDI::MachineControl::cmdDeferredPlay)); + _mmc->send (MIDI::MachineControlCommand (MIDI::MachineControl::cmdDeferredPlay)); } } @@ -1336,8 +1429,9 @@ Session::use_sync_source (Slave* new_slave) _slave = new_slave; DEBUG_TRACE (DEBUG::Slave, string_compose ("set new slave to %1\n", _slave)); - - send_full_time_code (_transport_frame); + + // need to queue this for next process() cycle + _send_timecode_update = true; boost::shared_ptr rl = routes.reader(); for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) { @@ -1378,7 +1472,7 @@ Session::switch_to_sync_source (SyncSource src) } try { - new_slave = new MTC_Slave (*this, *MIDI::Manager::instance()->mtc_input_port()); + new_slave = new MTC_Slave (*this, *_midi_ports->mtc_input_port()); } catch (failed_constructor& err) { @@ -1407,7 +1501,7 @@ Session::switch_to_sync_source (SyncSource src) } try { - new_slave = new MIDIClock_Slave (*this, *MIDI::Manager::instance()->midi_clock_input_port(), 24); + new_slave = new MIDIClock_Slave (*this, *_midi_ports->midi_clock_input_port(), 24); } catch (failed_constructor& err) { @@ -1415,8 +1509,8 @@ Session::switch_to_sync_source (SyncSource src) } break; - case JACK: - if (_slave && dynamic_cast(_slave)) { + case Engine: + if (_slave && dynamic_cast(_slave)) { return; } @@ -1424,7 +1518,7 @@ Session::switch_to_sync_source (SyncSource src) return; } - new_slave = new JACK_Slave (_engine.jack()); + new_slave = new Engine_Slave (*AudioEngine::instance()); break; default: @@ -1541,6 +1635,13 @@ Session::request_bounded_roll (framepos_t start, framepos_t end) lar.push_back (ar); request_play_range (&lar, true); } + +void +Session::set_requested_return_frame (framepos_t return_to) +{ + _requested_return_frame = return_to; +} + void Session::request_roll_at_and_return (framepos_t start, framepos_t return_to) { @@ -1614,23 +1715,13 @@ Session::allow_auto_play (bool yn) auto_play_legal = yn; } -void -Session::reset_jack_connection (jack_client_t* jack) -{ - JACK_Slave* js; - - if (_slave && ((js = dynamic_cast (_slave)) != 0)) { - js->reset_client (jack); - } -} - bool 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 ()) { + if (synced_to_engine () && config.get_jack_time_master ()) { _engine.transport_stop (); - } else if (!synced_to_jack ()) { + } else if (!synced_to_engine ()) { stop_transport (); } return true; @@ -1644,7 +1735,7 @@ Session::send_mmc_locate (framepos_t t) if (!_engine.freewheeling()) { Timecode::Time time; timecode_time_subframes (t, time); - MIDI::Manager::instance()->mmc()->send (MIDI::MachineControlCommand (time)); + _mmc->send (MIDI::MachineControlCommand (time)); } }