new transport option, "loop-is-mode" which optionally changes the role of the "play...
authorPaul Davis <paul@linuxaudiosystems.com>
Thu, 17 Apr 2014 13:47:06 +0000 (09:47 -0400)
committerPaul Davis <paul@linuxaudiosystems.com>
Thu, 17 Apr 2014 13:47:06 +0000 (09:47 -0400)
If enabled, then the button simply changes the behaviour of the "play" button rather than actually starting playback. If disabled
transport behaviour should be unchanged from before.

gtk2_ardour/ardour_ui.cc
gtk2_ardour/audio_region_view.cc
gtk2_ardour/rc_option_editor.cc
libs/ardour/ardour/rc_configuration_vars.h
libs/ardour/ardour/session.h
libs/ardour/session_process.cc
libs/ardour/session_transport.cc

index b4399b03fa932817bc2d2663ba0028bd6fd3bb15..ebdbc0651788fc11dbbdb9d7e357785cf9979829 100644 (file)
@@ -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_play_loop (false);
+
+       } else {
 
-                       _session->request_locate (looploc->start(), true);
-                       _session->request_play_loop (false);
+               /* 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 (false);
+                       _session->request_play_loop (true, true);
                }
-       } else {
-               _session->request_play_loop (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 ();
        }
 }
index 408c8e654abe7ce19057409d20a030fd089c402c..add985dd6f13f2c2301774373df7e588833ba23e 100644 (file)
@@ -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);
index d4a5c57705a5200f633f6a5c11319bf095012016..7d6be32e2212e3aa407e2e1c799509242bdcb73a 100644 (file)
@@ -1358,8 +1358,18 @@ RCOptionEditor::RCOptionEditor ()
        Gtkmm2ext::UI::instance()->set_tip (tsf->tip_widget(), 
                                            string_compose (_("<b>When enabled</b> %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(), 
+                                           (_("<b>When enabled</b> the loop button does not start playback but forces playback to always play the loop\n\n"
+                                              "<b>When disabled</b> 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"),
index 6b14680b42baf655d723dd0f6b0c7cc58d902e93..d290d8ebc844f541a1208cf6b671eb04842a47b7 100644 (file)
@@ -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)
index 20feb27001fcb4f585a10a78d28a9920c464c6c0..15af67ada7421e452be4b83f593093428f888f37 100644 (file)
@@ -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 ();
index 6bfb250aecbc4851aae2a8bf0d1578089f5ec98f..eb5c0de294f00cfbfe4c81b66949683930a13524 100644 (file)
@@ -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:
index 38ad5212359a7377e2e5cf045a11197b83fdc6ab..ea9f5d28dd6ee97e2beebb8e8cf65f8a95920c43 100644 (file)
@@ -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);
                }