loop handling changes: always turn off play_loop @ transport stop ; remove request_pl...
[ardour.git] / libs / ardour / session_transport.cc
index d5c9e99b8aec6b37db8b22f8be690278ad146eba..b29816be1b63ff2ee1a7733e1a4cc80d2bfd20e2 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 1999-2003 Paul Davis 
+    Copyright (C) 1999-2009 Paul Davis 
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -123,7 +123,7 @@ Session::request_play_loop (bool yn)
 
        ev = new Event (Event::SetLoop, Event::Add, Event::Immediate, 0, 0.0, yn);
        queue_event (ev);
-
+       
        if (!yn && Config->get_seamless_loop() && transport_rolling()) {
                // request an immediate locate to refresh the diskstreams
                // after disabling looping
@@ -207,8 +207,7 @@ Session::butler_transport_work ()
        }
 
        if (post_transport_work & PostTransportReverse) {
-
-
+               
                clear_clicks();
                cumulative_rf_motion = 0;
                reset_rf_scale (0);
@@ -386,6 +385,8 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished)
                     _requested_return_frame >= 0) &&
                    !(post_transport_work & PostTransportLocate)) {
 
+                       /* no explicit locate queued */
+
                        bool do_locate = false;
 
                        if (_requested_return_frame >= 0) {
@@ -393,7 +394,18 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished)
                                _requested_return_frame = -1;
                                do_locate = true;
                        } else {
-                               _transport_frame = last_stop_frame;
+                               if (play_loop && !synced_to_jack()) {
+                                       Location *location = _locations.auto_loop_location();
+                                       
+                                       if (location != 0) {
+                                               _transport_frame = location->start();
+                                               do_locate = true;
+                                       } else {
+                                               _transport_frame = last_stop_frame;
+                                       }
+                               } else {
+                                       _transport_frame = last_stop_frame;
+                               }
                                _requested_return_frame = -1;
                        }
 
@@ -437,6 +449,8 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished)
                _requested_return_frame = -1;
        }
 
+        have_looped = false; 
+
         send_full_time_code ();
        deliver_mmc (MIDI::MachineControl::cmdStop, 0);
        deliver_mmc (MIDI::MachineControl::cmdLocate, _transport_frame);
@@ -480,9 +494,7 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished)
 
        if (post_transport_work & PostTransportStop) { 
                _play_range = false;
-
-               /* do not turn off autoloop on stop */
-               
+               play_loop = false;
        }
 
         nframes_t tf = _transport_frame;
@@ -527,7 +539,9 @@ Session::set_play_loop (bool yn)
 {
        /* Called from event-handling context */
        
-       if ((actively_recording() && yn) || _locations.auto_loop_location() == 0) {
+       Location *loc;
+
+       if ((actively_recording() && yn) || (loc = _locations.auto_loop_location()) == 0) {
                return;
        }
        
@@ -543,10 +557,8 @@ Session::set_play_loop (bool yn)
        
        if ((play_loop = yn)) {
 
-               Location *loc;
 
-               
-               if ((loc = _locations.auto_loop_location()) != 0) {
+               if (loc) {
 
                        if (Config->get_seamless_loop()) {
                                // set all diskstreams to use internal looping
@@ -567,25 +579,17 @@ Session::set_play_loop (bool yn)
                                }
                        }
                        
-                       /* stick in the loop event */
+                       /* put the loop event into the event list */
                        
                        Event* event = new Event (Event::AutoLoop, Event::Replace, loc->end(), loc->start(), 0.0f);
                        merge_event (event);
 
-                       /* locate to start of loop and roll if current pos is outside of the loop range */
-                       if (_transport_frame < loc->start() || _transport_frame > loc->end()) {
-                               event = new Event (Event::LocateRoll, Event::Add, Event::Immediate, loc->start(), 0, !synced_to_jack());
-                               merge_event (event);
-                       }
-                       else {
-                               // locate to current position (+ 1 to force reload)
-                               event = new Event (Event::LocateRoll, Event::Add, Event::Immediate, _transport_frame + 1, 0, !synced_to_jack());
-                               merge_event (event);
-                       }
+                       /* locate to start of loop and roll */
+                       event = new Event (Event::LocateRoll, Event::Add, Event::Immediate, loc->start(), 0, !synced_to_jack());
+                       merge_event (event);
                }
 
 
-
        } else {
                clear_events (Event::AutoLoop);
 
@@ -640,6 +644,25 @@ Session::start_locate (nframes_t target_frame, bool with_roll, bool with_flush,
        }
 }
 
+int
+Session::micro_locate (nframes_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)) {
+                       return -1;
+               }
+       }
+
+       for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
+               (*i)->internal_playback_seek (distance);
+       }
+       
+       _transport_frame += distance;
+       return 0;
+}
+
 void
 Session::locate (nframes_t target_frame, bool with_roll, bool with_flush, bool with_loop)
 {
@@ -674,7 +697,7 @@ Session::locate (nframes_t target_frame, bool with_roll, bool with_flush, bool w
        } 
 
        if ( !with_loop || loop_changing) {
-
+               
                post_transport_work = PostTransportWork (post_transport_work | PostTransportLocate);
                
                if (with_roll) {
@@ -747,12 +770,14 @@ Session::locate (nframes_t target_frame, bool with_roll, bool with_flush, bool w
                                        }
                                }
                        }
-
+                       have_looped = true;
                        TransportLooped(); // EMIT SIGNAL
                }
        }
        
        loop_changing = false;
+
+       _send_smpte_update = true;
 }
 
 void
@@ -844,6 +869,7 @@ Session::set_transport_speed (float speed, bool abort)
 
                if ((_transport_speed && speed * _transport_speed < 0.0f) || (_last_transport_speed * speed < 0.0f) || (_last_transport_speed == 0.0f && speed < 0.0f)) {
                        post_transport_work = PostTransportWork (post_transport_work | PostTransportReverse);
+                       last_stop_frame = _transport_frame;
                }
                
                _last_transport_speed = _transport_speed;
@@ -907,6 +933,7 @@ void
 Session::start_transport ()
 {
        _last_roll_location = _transport_frame;
+       have_looped = false;
 
        /* if record status is Enabled, move it to Recording. if its
           already Recording, move it to Disabled. 
@@ -929,18 +956,6 @@ Session::start_transport ()
                break;
        }
 
-       if (!synced_to_jack() || _exporting) {
-               actually_start_transport ();
-       } else {
-               waiting_to_start = true;
-       }
-}
-
-void
-Session::actually_start_transport ()
-{
-       waiting_to_start = false;
-
        transport_sub_state |= PendingDeclickIn;
        _transport_speed = 1.0;
        
@@ -1006,7 +1021,7 @@ Session::reset_rf_scale (nframes_t motion)
 }
 
 void
-Session::set_slave_source (SlaveSource src)
+Session::set_slave_source (SlaveSource src, bool stop_the_transport)
 {
        bool reverse = false;
        bool non_rt_required = false;
@@ -1031,7 +1046,9 @@ Session::set_slave_source (SlaveSource src)
 
        switch (src) {
        case None:
-               stop_transport ();
+               if (stop_the_transport) {
+                       stop_transport ();
+               }
                break;
                
        case MTC:
@@ -1223,11 +1240,16 @@ Session::engine_halted ()
        g_atomic_int_set (&butler_should_do_transport_work, 0);
        post_transport_work = PostTransportWork (0);
        stop_butler ();
-       
+
        realtime_stop (false);
        non_realtime_stop (false, 0, ignored);
        transport_sub_state = 0;
 
+       if (synced_to_jack()) {
+               /* transport is already stopped, hence the second argument */
+               set_slave_source (None, false);
+       }
+
        TransportStateChange (); /* EMIT SIGNAL */
 }
 
@@ -1258,6 +1280,11 @@ Session::update_latency_compensation (bool with_stop, bool abort)
 
        _worst_track_latency = 0;
 
+#undef DEBUG_LATENCY
+#ifdef DEBUG_LATENCY
+       cerr << "\n---------------------------------\nUPDATE LATENCY\n";
+#endif
+
        boost::shared_ptr<RouteList> r = routes.reader ();
 
        for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
@@ -1278,6 +1305,10 @@ Session::update_latency_compensation (bool with_stop, bool abort)
                }
        }
 
+#ifdef DEBUG_LATENCY
+       cerr << "\tworst was " << _worst_track_latency << endl;
+#endif
+
        for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
                (*i)->set_latency_delay (_worst_track_latency);
        }