a) fix special button press handling for solo+mute buttons
[ardour.git] / libs / ardour / session_transport.cc
index 342b6e1a5279e6ca5a838b134240431c62eb7760..2f9f8257f9344d3d8e3f2e38515861ec6e18cfa7 100644 (file)
@@ -189,17 +189,21 @@ Session::realtime_stop (bool abort)
        _clear_event_type (Event::RangeStop);
        _clear_event_type (Event::RangeLocate);
 
-       disable_record ();
+       disable_record (true);
 
        reset_slave_state ();
-
+               
        _transport_speed = 0;
+
        transport_sub_state = (auto_return ? AutoReturning : 0);
 }
 
 void
 Session::butler_transport_work ()
 {
+       RWLockMonitor rm (route_lock, false, __LINE__, __FILE__);
+       RWLockMonitor dsm (diskstream_lock, false, __LINE__, __FILE__);
+               
        if (post_transport_work & PostTransportCurveRealloc) {
                for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
                        (*i)->curve_reallocate();
@@ -253,7 +257,7 @@ Session::butler_transport_work ()
 void
 Session::non_realtime_set_speed ()
 {
-       LockMonitor lm (diskstream_lock, __LINE__, __FILE__);
+       RWLockMonitor lm (diskstream_lock, false, __LINE__, __FILE__);
 
        for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
                (*i)->non_realtime_set_speed ();
@@ -263,7 +267,7 @@ Session::non_realtime_set_speed ()
 void
 Session::non_realtime_overwrite ()
 {
-       LockMonitor lm (diskstream_lock, __LINE__, __FILE__);
+       RWLockMonitor lm (diskstream_lock, false, __LINE__, __FILE__);
 
        for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
                if ((*i)->pending_overwrite) {
@@ -278,9 +282,9 @@ 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) {
                if ((*i)->get_captured_frames () != 0) {
                        did_record = true;
@@ -382,8 +386,18 @@ Session::non_realtime_stop (bool abort)
        deliver_mmc (MIDI::MachineControl::cmdLocate, _transport_frame);
 
        if (did_record) {
-               atomic_set (&_record_status, Disabled);
-               RecordDisabled (); /* EMIT SIGNAL */
+
+               /* XXX its a little odd that we're doing this here
+                  when realtime_stop(), which has already executed,
+                  will have done this.
+               */
+
+               if (!Config->get_latched_record_enable()) {
+                       atomic_set (&_record_status, Disabled);
+               } else {
+                       atomic_set (&_record_status, Enabled);
+               }
+               RecordStateChanged (); /* emit signal */
        }
        
        if ((post_transport_work & PostTransportLocate) && get_record_enabled()) {
@@ -391,8 +405,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);
        }
@@ -448,7 +466,7 @@ Session::set_auto_loop (bool yn)
 {
        /* Called from event-handling context */
        
-       if (actively_recording() || _locations.auto_loop_location() == 0) {
+       if ((actively_recording() && yn) || _locations.auto_loop_location() == 0) {
                return;
        }
        
@@ -603,18 +621,51 @@ Session::locate (jack_nframes_t target_frame, bool with_roll, bool with_flush, b
 
        } else {
 
-               /* XXX i don't know where else to put this. something has to clear the
-                  current clicks, and without deadlocking. clear_clicks() takes
-                  the route lock which would deadlock in this context.
-               */
+               /* this is functionally what clear_clicks() does but with a tentative lock */
 
-               for (Clicks::iterator i = clicks.begin(); i != clicks.end(); ++i) {
-                       delete *i;
-               }
+               TentativeRWLockMonitor clickm (click_lock, true, __LINE__, __FILE__);
+       
+               if (clickm.locked()) {
+                       
+                       for (Clicks::iterator i = clicks.begin(); i != clicks.end(); ++i) {
+                               delete *i;
+                       }
                
-               clicks.clear ();
+                       clicks.clear ();
+               }
        }
 
+       if (with_roll) {
+               /* switch from input if we're going to roll */
+               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) {
+                               if ((*i)->record_enabled ()) {
+                                       //cerr << "switching from input" << __FILE__ << __LINE__ << endl << endl;
+                                       (*i)->monitor_input (!auto_input);
+                               }
+                       }
+               }
+       } else {
+               /* otherwise we're going to stop, so do the opposite */
+               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) {
+                               if ((*i)->record_enabled ()) {
+                                       //cerr << "switching to input" << __FILE__ << __LINE__ << endl << endl;
+                                       (*i)->monitor_input (true);
+                               }
+                       }
+               }
+       }
 
        /* cancel autoloop if transport pos outside of loop range */
        if (auto_loop) {
@@ -644,6 +695,21 @@ Session::set_transport_speed (float speed, bool abort)
 
        if (transport_rolling() && speed == 0.0) {
 
+               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) {
+                               if ((*i)->record_enabled ()) {
+                                       //cerr << "switching to input" << __FILE__ << __LINE__ << endl << endl;
+                                       (*i)->monitor_input (true);     
+                               }
+                       }
+               }
+
                if (synced_to_jack ()) {
                        _engine.transport_stop ();
                } else {
@@ -652,6 +718,20 @@ Session::set_transport_speed (float speed, bool abort)
 
        } else if (transport_stopped() && speed == 1.0) {
 
+               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) {
+                               if (auto_input && (*i)->record_enabled ()) {
+                                       //cerr << "switching from input" << __FILE__ << __LINE__ << endl << endl;
+                                       (*i)->monitor_input (false);    
+                               }
+                       }
+               }
+
                if (synced_to_jack()) {
                        _engine.transport_start ();
                } else {
@@ -690,7 +770,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) {
                        if ((*i)->realtime_set_speed ((*i)->speed(), true)) {
                                post_transport_work = PostTransportWork (post_transport_work | PostTransportSpeed);
@@ -759,7 +839,7 @@ Session::start_transport ()
                break;
 
        case Recording:
-               disable_record ();
+               disable_record (false);
                break;
 
        default:
@@ -1102,8 +1182,8 @@ Session::update_latency_compensation (bool with_stop, bool abort)
                return;
        }
 
-       LockMonitor lm (route_lock, __LINE__, __FILE__);
-       LockMonitor lm2 (diskstream_lock, __LINE__, __FILE__);
+       RWLockMonitor lm (route_lock, false, __LINE__, __FILE__);
+       RWLockMonitor lm2 (diskstream_lock, false, __LINE__, __FILE__);
        _worst_track_latency = 0;
 
        for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {