Merging from trunk
[ardour.git] / libs / ardour / session_transport.cc
index e2a9f2389009f5a30e512211cff6cd1c9e6c2983..376dee11a2ae43e11a65e39a6bc3376fdea8ca1a 100644 (file)
@@ -27,7 +27,7 @@
 
 #include <pbd/undo.h>
 #include <pbd/error.h>
-#include <pbd/lockmonitor.h>
+#include <glibmm/thread.h>
 #include <pbd/pthread_utils.h>
 
 #include <midi++/mmc.h>
@@ -36,7 +36,7 @@
 #include <ardour/ardour.h>
 #include <ardour/audioengine.h>
 #include <ardour/session.h>
-#include <ardour/diskstream.h>
+#include <ardour/audio_diskstream.h>
 #include <ardour/auditioner.h>
 #include <ardour/slave.h>
 #include <ardour/location.h>
@@ -46,6 +46,7 @@
 using namespace std;
 using namespace ARDOUR;
 using namespace sigc;
+using namespace PBD;
 
 void
 Session::request_input_change_handling ()
@@ -78,7 +79,7 @@ Session::request_transport_speed (float speed)
 }
 
 void
-Session::request_diskstream_speed (DiskStream& ds, float speed)
+Session::request_diskstream_speed (AudioDiskstream& ds, float speed)
 {
        Event* ev = new Event (Event::SetDiskstreamSpeed, Event::Add, Event::Immediate, 0, speed);
        ev->set_ptr (&ds);
@@ -165,22 +166,11 @@ Session::realtime_stop (bool abort)
                decrement_transport_position (_worst_output_latency);
 #endif
 
-               if (_transport_frame > current_end_frame()) {
-                       
-                       /* first capture resets end location; later captures can only extend the length */
+               /* the duration change is not guaranteed to have happened, but is likely */
 
-                       if (_end_location_is_free) {
-                               end_location->set_end (_transport_frame);
-                               _end_location_is_free = false;
-                       } else if (_transport_frame > end_location->start()) {
-                               end_location->set_end (_transport_frame);
-                       }
-
-                       post_transport_work = PostTransportWork (post_transport_work | PostTransportDuration);
-               }
+               post_transport_work = PostTransportWork (post_transport_work | PostTransportDuration);
        }
 
-
        if (abort) {
                post_transport_work = PostTransportWork (post_transport_work | PostTransportAbort);
        }
@@ -189,7 +179,7 @@ Session::realtime_stop (bool abort)
        _clear_event_type (Event::RangeStop);
        _clear_event_type (Event::RangeLocate);
 
-       disable_record ();
+       disable_record (true);
 
        reset_slave_state ();
                
@@ -201,8 +191,8 @@ Session::realtime_stop (bool abort)
 void
 Session::butler_transport_work ()
 {
-       RWLockMonitor rm (route_lock, false, __LINE__, __FILE__);
-       RWLockMonitor dsm (diskstream_lock, false, __LINE__, __FILE__);
+       Glib::RWLock::ReaderLock rm (route_lock);
+       Glib::RWLock::ReaderLock dsm (diskstream_lock);
                
        if (post_transport_work & PostTransportCurveRealloc) {
                for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
@@ -211,7 +201,7 @@ Session::butler_transport_work ()
        }
 
        if (post_transport_work & PostTransportInputChange) {
-               for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
+               for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) {
                        (*i)->non_realtime_input_change ();
                }
        }
@@ -227,7 +217,7 @@ Session::butler_transport_work ()
                cumulative_rf_motion = 0;
                reset_rf_scale (0);
 
-               for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
+               for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) {
                        if (!(*i)->hidden()) {
                                if ((*i)->speed() != 1.0f || (*i)->speed() != -1.0f) {
                                        (*i)->seek ((jack_nframes_t) (_transport_frame * (double) (*i)->speed()));
@@ -251,15 +241,15 @@ Session::butler_transport_work ()
                non_realtime_set_audition ();
        }
 
-       atomic_dec (&butler_should_do_transport_work);
+       g_atomic_int_dec_and_test (&butler_should_do_transport_work);
 }
 
 void
 Session::non_realtime_set_speed ()
 {
-       RWLockMonitor lm (diskstream_lock, false, __LINE__, __FILE__);
+       Glib::RWLock::ReaderLock lm (diskstream_lock);
 
-       for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
+       for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) {
                (*i)->non_realtime_set_speed ();
        }
 }
@@ -267,9 +257,9 @@ Session::non_realtime_set_speed ()
 void
 Session::non_realtime_overwrite ()
 {
-       RWLockMonitor lm (diskstream_lock, false, __LINE__, __FILE__);
+       Glib::RWLock::ReaderLock lm (diskstream_lock);
 
-       for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
+       for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) {
                if ((*i)->pending_overwrite) {
                        (*i)->overwrite_existing_buffers ();
                }
@@ -282,10 +272,10 @@ Session::non_realtime_stop (bool abort)
        struct tm* now;
        time_t     xnow;
        bool       did_record;
-
+       
        did_record = false;
-
-       for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
+       
+       for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) {
                if ((*i)->get_captured_frames () != 0) {
                        did_record = true;
                        break;
@@ -307,25 +297,38 @@ Session::non_realtime_stop (bool abort)
 
        if (did_record) {
                begin_reversible_command ("capture");
-
+               
                Location* loc = _locations.end_location();
+               bool change_end = false;
 
-               if (loc && !_have_captured) {
-                               
-                       /* first capture.
-                          
-                          note: later captures that extend the session length get
-                          handled because of playlist length changes.
-                       */
+               if (_transport_frame < loc->end()) {
+
+                       /* stopped recording before current end */
+
+                       if (_end_location_is_free) {
+
+                               /* first capture for this session, move end back to where we are */
+
+                               change_end = true;
+                       } 
+
+               } else if (_transport_frame > loc->end()) {
                        
-                 add_undo (sigc::retype_return<void>(sigc::bind (mem_fun (*loc, &Location::set_end), loc->end())));
-                 add_redo (sigc::retype_return<void>(sigc::bind (mem_fun (*loc, &Location::set_end), _transport_frame)));
+                       /* stopped recording after the current end, extend it */
+
+                       change_end = true;
+               }
+               
+               if (change_end) {
+                       add_undo (sigc::retype_return<void>(sigc::bind (mem_fun (*loc, &Location::set_end), loc->end())));
+                       add_redo (sigc::retype_return<void>(sigc::bind (mem_fun (*loc, &Location::set_end), _transport_frame)));
                }
 
+               _end_location_is_free = false;
                _have_captured = true;
        }
 
-       for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
+       for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) {
                (*i)->transport_stopped (*now, xnow, abort);
        }
        
@@ -362,7 +365,7 @@ Session::non_realtime_stop (bool abort)
        }
 #endif
 
-               for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
+               for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) {
                        if (!(*i)->hidden()) {
                                if ((*i)->speed() != 1.0f || (*i)->speed() != -1.0f) {
                                        (*i)->seek ((jack_nframes_t) (_transport_frame * (double) (*i)->speed()));
@@ -393,9 +396,9 @@ Session::non_realtime_stop (bool abort)
                */
 
                if (!Config->get_latched_record_enable()) {
-                       atomic_set (&_record_status, Disabled);
+                       g_atomic_int_set (&_record_status, Disabled);
                } else {
-                       atomic_set (&_record_status, Enabled);
+                       g_atomic_int_set (&_record_status, Enabled);
                }
                RecordStateChanged (); /* emit signal */
        }
@@ -405,8 +408,12 @@ Session::non_realtime_stop (bool abort)
                save_state ("", true);
        }
 
-       /* save the current state of things if appropriate */
+        /* always try to get rid of this */
+
+        remove_pending_capture_state ();
        
+       /* save the current state of things if appropriate */
+
        if (did_record) {
                save_state (_current_snapshot_name);
        }
@@ -485,7 +492,7 @@ Session::set_auto_loop (bool yn)
 
                        if (seamless_loop) {
                                // set all diskstreams to use internal looping
-                               for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
+                               for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) {
                                        if (!(*i)->hidden()) {
                                                (*i)->set_loop (loc);
                                        }
@@ -493,7 +500,7 @@ Session::set_auto_loop (bool yn)
                        }
                        else {
                                // set all diskstreams to NOT use internal looping
-                               for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
+                               for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) {
                                        if (!(*i)->hidden()) {
                                                (*i)->set_loop (0);
                                        }
@@ -523,7 +530,7 @@ Session::set_auto_loop (bool yn)
                clear_events (Event::AutoLoop);
 
                // set all diskstreams to NOT use internal looping
-               for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
+               for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) {
                        if (!(*i)->hidden()) {
                                (*i)->set_loop (0);
                        }
@@ -619,7 +626,7 @@ Session::locate (jack_nframes_t target_frame, bool with_roll, bool with_flush, b
 
                /* this is functionally what clear_clicks() does but with a tentative lock */
 
-               TentativeRWLockMonitor clickm (click_lock, true, __LINE__, __FILE__);
+               Glib::RWLock::WriterLock clickm (click_lock, Glib::TRY_LOCK);
        
                if (clickm.locked()) {
                        
@@ -638,8 +645,8 @@ Session::locate (jack_nframes_t target_frame, bool with_roll, bool with_flush, b
                           a non-tentative rwlock here,  because the action must occur.
                           The rarity and short potential lock duration makes this "OK"
                        */
-                       RWLockMonitor dsm (diskstream_lock, false, __LINE__, __FILE__);
-                       for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
+                       Glib::RWLock::ReaderLock dsm (diskstream_lock);
+                       for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) {
                                if ((*i)->record_enabled ()) {
                                        //cerr << "switching from input" << __FILE__ << __LINE__ << endl << endl;
                                        (*i)->monitor_input (!auto_input);
@@ -653,8 +660,8 @@ Session::locate (jack_nframes_t target_frame, bool with_roll, bool with_flush, b
                           a non-tentative rwlock here,  because the action must occur.
                           The rarity and short potential lock duration makes this "OK"
                        */
-                       RWLockMonitor dsm (diskstream_lock, false, __LINE__, __FILE__);
-                       for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
+                       Glib::RWLock::ReaderLock dsm (diskstream_lock);
+                       for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) {
                                if ((*i)->record_enabled ()) {
                                        //cerr << "switching to input" << __FILE__ << __LINE__ << endl << endl;
                                        (*i)->monitor_input (true);
@@ -697,8 +704,8 @@ Session::set_transport_speed (float speed, bool abort)
                           a non-tentative rwlock here,  because the action must occur.
                           The rarity and short potential lock duration makes this "OK"
                        */
-                       RWLockMonitor dsm (diskstream_lock, false, __LINE__, __FILE__);
-                       for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
+                       Glib::RWLock::ReaderLock dsm (diskstream_lock);
+                       for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) {
                                if ((*i)->record_enabled ()) {
                                        //cerr << "switching to input" << __FILE__ << __LINE__ << endl << endl;
                                        (*i)->monitor_input (true);     
@@ -714,13 +721,17 @@ Session::set_transport_speed (float speed, bool abort)
 
        } else if (transport_stopped() && speed == 1.0) {
 
+               if (!get_record_enabled() && Config->get_stop_at_session_end() && _transport_frame >= current_end_frame()) {
+                       return;
+               }
+
                if (Config->get_use_hardware_monitoring()) {
                        /* Even though this is called from RT context we are using
                           a non-tentative rwlock here,  because the action must occur.
                           The rarity and short potential lock duration makes this "OK"
                        */
-                       RWLockMonitor dsm (diskstream_lock, false, __LINE__, __FILE__);
-                       for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
+                       Glib::RWLock::ReaderLock dsm (diskstream_lock);
+                       for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) {
                                if (auto_input && (*i)->record_enabled ()) {
                                        //cerr << "switching from input" << __FILE__ << __LINE__ << endl << endl;
                                        (*i)->monitor_input (false);    
@@ -736,6 +747,10 @@ Session::set_transport_speed (float speed, bool abort)
 
        } else {
 
+               if (!get_record_enabled() && Config->get_stop_at_session_end() && _transport_frame >= current_end_frame()) {
+                       return;
+               }
+
                if ((synced_to_jack()) && speed != 0.0 && speed != 1.0) {
                        warning << _("Global varispeed cannot be supported while Ardour is connected to JACK transport control")
                                << endmsg;
@@ -767,7 +782,7 @@ Session::set_transport_speed (float speed, bool abort)
                _last_transport_speed = _transport_speed;
                _transport_speed = speed;
                
-               for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
+               for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) {
                        if ((*i)->realtime_set_speed ((*i)->speed(), true)) {
                                post_transport_work = PostTransportWork (post_transport_work | PostTransportSpeed);
                        }
@@ -835,7 +850,7 @@ Session::start_transport ()
                break;
 
        case Recording:
-               disable_record ();
+               disable_record (false);
                break;
 
        default:
@@ -857,7 +872,7 @@ Session::actually_start_transport ()
        transport_sub_state |= PendingDeclickIn;
        _transport_speed = 1.0;
        
-       for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
+       for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) {
                (*i)->realtime_set_speed ((*i)->speed(), true);
        }
 
@@ -932,17 +947,17 @@ Session::set_slave_source (SlaveSource src, jack_nframes_t frame)
        bool reverse = false;
        bool non_rt_required = false;
 
+       if (src == _slave_type) {
+               return 0;
+       } 
+
        if (_transport_speed) {
                error << _("please stop the transport before adjusting slave settings") << endmsg;
                /* help out non-MVC friendly UI's by telling them the slave type changed */
-                ControlChanged (SlaveType); /* EMIT SIGNAL */
+               ControlChanged (SlaveType); /* EMIT SIGNAL */
                return 0;
        }
 
-       if (src == _slave_type) {
-               return 0;
-       } 
-
 //     if (src == JACK && Config->get_jack_time_master()) {
 //             return -1;
 //     }
@@ -987,7 +1002,7 @@ Session::set_slave_source (SlaveSource src, jack_nframes_t frame)
        
        _slave_type = src;
 
-       for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
+       for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) {
                if (!(*i)->hidden()) {
                        if ((*i)->realtime_set_speed ((*i)->speed(), true)) {
                                non_rt_required = true;
@@ -1019,7 +1034,7 @@ Session::reverse_diskstream_buffers ()
 }
 
 void
-Session::set_diskstream_speed (DiskStream* stream, float speed)
+Session::set_diskstream_speed (AudioDiskstream* stream, float speed)
 {
        if (stream->realtime_set_speed (speed, false)) {
                post_transport_work = PostTransportWork (post_transport_work | PostTransportSpeed);
@@ -1142,7 +1157,7 @@ Session::engine_halted ()
           the picture.
        */
 
-       atomic_set (&butler_should_do_transport_work, 0);
+       g_atomic_int_set (&butler_should_do_transport_work, 0);
        post_transport_work = PostTransportWork (0);
        stop_butler ();
        
@@ -1178,14 +1193,14 @@ Session::update_latency_compensation (bool with_stop, bool abort)
                return;
        }
 
-       RWLockMonitor lm (route_lock, false, __LINE__, __FILE__);
-       RWLockMonitor lm2 (diskstream_lock, false, __LINE__, __FILE__);
+       Glib::RWLock::ReaderLock lm (route_lock);
+       Glib::RWLock::ReaderLock lm2 (diskstream_lock);
        _worst_track_latency = 0;
 
        for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
                if (with_stop) {
-                       (*i)->transport_stopped (abort, (post_transport_work & PostTransportLocate), 
-                                                (!(post_transport_work & PostTransportLocate) || pending_locate_flush));
+                       (*i)->handle_transport_stopped (abort, (post_transport_work & PostTransportLocate), 
+                                                       (!(post_transport_work & PostTransportLocate) || pending_locate_flush));
                }
 
                jack_nframes_t old_latency = (*i)->signal_latency ();
@@ -1215,7 +1230,7 @@ Session::update_latency_compensation (bool with_stop, bool abort)
        /* reflect any changes in latencies into capture offsets
        */
        
-       for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
+       for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) {
                (*i)->set_capture_offset ();
        }
 }