diff --git a/gtk2_ardour/ardour_ui.cc b/gtk2_ardour/ardour_ui.cc index b4399b03fa..ebdbc06517 100644 --- a/gtk2_ardour/ardour_ui.cc +++ b/gtk2_ardour/ardour_ui.cc @@ -1882,12 +1882,25 @@ ARDOUR_UI::transport_roll () bool rolling = _session->transport_rolling(); if (_session->get_play_loop()) { - /* XXX it is not possible to just leave seamless loop and keep - playing at present (nov 4th 2009) + + /* If loop playback is not a mode, then we should cancel + it when this action is requested. If it is a mode + we just leave it in place. */ - if (!Config->get_seamless_loop()) { - _session->request_play_loop (false, true); - } + + if (!Config->get_loop_is_mode()) { + /* XXX it is not possible to just leave seamless loop and keep + playing at present (nov 4th 2009) + */ + if (!Config->get_seamless_loop()) { + /* stop loop playback and stop rolling */ + _session->request_play_loop (false, true); + } else if (rolling) { + /* stop loop playback but keep rolling */ + _session->request_play_loop (false, false); + } + } + } else if (_session->get_play_range () && !Config->get_always_play_range()) { /* stop playing a range if we currently are */ _session->request_play_range (0, true); @@ -1944,7 +1957,7 @@ ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode) /* disk buffers are normal, so we can keep playing */ affect_transport = false; } - _session->request_play_loop (false, true); + _session->request_play_loop (false, affect_transport); } else if (_session->get_play_range ()) { affect_transport = false; _session->request_play_range (0, true); @@ -1975,16 +1988,23 @@ ARDOUR_UI::toggle_session_auto_loop () if (_session->get_play_loop()) { - if (_session->transport_rolling()) { + /* looping enabled, our job is to disable it */ - _session->request_locate (looploc->start(), true); - _session->request_play_loop (false); + _session->request_play_loop (false); - } else { - _session->request_play_loop (false); - } } else { - _session->request_play_loop (true); + + /* looping not enabled, our job is to enable it. + + loop-is-NOT-mode: this action always starts the transport rolling. + loop-IS-mode: this action simply sets the loop play mechanism, but + does not start transport. + */ + if (Config->get_loop_is_mode()) { + _session->request_play_loop (true, false); + } else { + _session->request_play_loop (true, true); + } } //show the loop markers @@ -2112,7 +2132,11 @@ ARDOUR_UI::map_transport_state () auto_loop_button.set_active (true); play_selection_button.set_active (false); - roll_button.set_active (false); + if (Config->get_loop_is_mode()) { + roll_button.set_active (true); + } else { + roll_button.set_active (false); + } } else { @@ -2134,7 +2158,11 @@ ARDOUR_UI::map_transport_state () stop_button.set_active (true); roll_button.set_active (false); play_selection_button.set_active (false); - auto_loop_button.set_active (false); + if (Config->get_loop_is_mode ()) { + auto_loop_button.set_active (_session->get_play_loop()); + } else { + auto_loop_button.set_active (false); + } update_disk_space (); } } diff --git a/gtk2_ardour/audio_region_view.cc b/gtk2_ardour/audio_region_view.cc index 408c8e654a..add985dd6f 100644 --- a/gtk2_ardour/audio_region_view.cc +++ b/gtk2_ardour/audio_region_view.cc @@ -1434,6 +1434,12 @@ AudioRegionView::set_one_waveform_color (ArdourCanvas::WaveView* wave) ArdourCanvas::color_to_rgba (fill, r, g, b, a); fill = ArdourCanvas::rgba_to_color (r, g, b, 0.85); /* magic number, not user controllable */ outline = ARDOUR_UI::config()->get_canvasvar_WaveForm(); + + if (!Config->get_show_name_highlight()) { + /* recolor name text because it needs to contrast with + the waveform background, not the name highlight. + */ + } } wave->set_fill_color (fill); diff --git a/gtk2_ardour/rc_option_editor.cc b/gtk2_ardour/rc_option_editor.cc index d4a5c57705..7d6be32e22 100644 --- a/gtk2_ardour/rc_option_editor.cc +++ b/gtk2_ardour/rc_option_editor.cc @@ -1358,8 +1358,18 @@ RCOptionEditor::RCOptionEditor () Gtkmm2ext::UI::instance()->set_tip (tsf->tip_widget(), string_compose (_("When enabled %1 will stop recording if an over- or underrun is detected by the audio engine"), PROGRAM_NAME)); - add_option (_("Transport"), tsf); + tsf = new BoolOption ( + "loop-is-mode", + _("Play loop is a transport mode"), + sigc::mem_fun (*_rc_config, &RCConfiguration::get_loop_is_mode), + sigc::mem_fun (*_rc_config, &RCConfiguration::set_loop_is_mode) + ); + Gtkmm2ext::UI::instance()->set_tip (tsf->tip_widget(), + (_("When enabled the loop button does not start playback but forces playback to always play the loop\n\n" + "When disabled the loop button starts playing the loop, but stop then cancels loop playback"))); + add_option (_("Transport"), tsf); + tsf = new BoolOption ( "create-xrun-marker", _("Create markers where xruns occur"), diff --git a/libs/ardour/ardour/rc_configuration_vars.h b/libs/ardour/ardour/rc_configuration_vars.h index 6b14680b42..d290d8ebc8 100644 --- a/libs/ardour/ardour/rc_configuration_vars.h +++ b/libs/ardour/ardour/rc_configuration_vars.h @@ -133,6 +133,7 @@ CONFIG_VARIABLE (bool, stop_recording_on_xrun, "stop-recording-on-xrun", false) CONFIG_VARIABLE (bool, create_xrun_marker, "create-xrun-marker", true) CONFIG_VARIABLE (bool, stop_at_session_end, "stop-at-session-end", false) CONFIG_VARIABLE (bool, seamless_loop, "seamless-loop", false) +CONFIG_VARIABLE (bool, loop_is_mode, "loop-is-mode", false) CONFIG_VARIABLE (framecnt_t, preroll, "preroll", 0) CONFIG_VARIABLE (framecnt_t, postroll, "postroll", 0) CONFIG_VARIABLE (float, rf_speed, "rf-speed", 2.0f) diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h index 20feb27001..15af67ada7 100644 --- a/libs/ardour/ardour/session.h +++ b/libs/ardour/ardour/session.h @@ -1262,7 +1262,7 @@ class LIBARDOUR_API Session : public PBD::StatefulDestructible, public PBD::Scop int start_midi_thread (); - void set_play_loop (bool yn); + void set_play_loop (bool yn, double speed); void unset_play_loop (); void overwrite_some_buffers (Track *); void flush_all_inserts (); diff --git a/libs/ardour/session_process.cc b/libs/ardour/session_process.cc index 6bfb250aec..eb5c0de294 100644 --- a/libs/ardour/session_process.cc +++ b/libs/ardour/session_process.cc @@ -1010,7 +1010,7 @@ Session::process_event (SessionEvent* ev) switch (ev->type) { case SessionEvent::SetLoop: - set_play_loop (ev->yes_or_no); + set_play_loop (ev->yes_or_no, ev->speed); break; case SessionEvent::AutoLoop: diff --git a/libs/ardour/session_transport.cc b/libs/ardour/session_transport.cc index 38ad521235..ea9f5d28dd 100644 --- a/libs/ardour/session_transport.cc +++ b/libs/ardour/session_transport.cc @@ -30,6 +30,7 @@ #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" @@ -40,6 +41,7 @@ #include "ardour/click.h" #include "ardour/debug.h" #include "ardour/location.h" +#include "ardour/profile.h" #include "ardour/session.h" #include "ardour/slave.h" #include "ardour/operations.h" @@ -158,10 +160,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") @@ -169,14 +172,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); + } } } @@ -531,8 +564,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; @@ -589,8 +620,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 */ @@ -657,8 +690,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 */ @@ -723,7 +758,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 */ @@ -782,12 +817,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 { @@ -983,7 +1030,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()) { @@ -1080,12 +1129,27 @@ 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); }