Merged with trunk revision 600
[ardour.git] / libs / ardour / session_process.cc
index 835d4ccdc2cdbb415b4a1589e8eba1362e0dfb8e..daa3a1d380a4493ea65da0e93325e08109c11857 100644 (file)
 #include <algorithm>
 #include <unistd.h>
 
-#include <ardour/timestamps.h>
-
 #include <pbd/error.h>
-#include <pbd/atomic.h>
-#include <pbd/lockmonitor.h>
+
+#include <glibmm/thread.h>
 
 #include <ardour/ardour.h>
 #include <ardour/session.h>
-#include <ardour/diskstream.h>
+#include <ardour/timestamps.h>
+#include <ardour/audio_diskstream.h>
 #include <ardour/audioengine.h>
 #include <ardour/slave.h>
 #include <ardour/auditioner.h>
 #include <ardour/cycles.h>
 #include <ardour/cycle_timer.h>
 
+#include <midi++/manager.h>
+
 #include "i18n.h"
 
 using namespace ARDOUR;
@@ -47,6 +48,10 @@ using namespace std;
 void
 Session::process (jack_nframes_t nframes)
 {
+       //cerr << "CYCLE START " << _transport_frame << "-------------------" << endl;
+       
+       MIDI::Manager::instance()->cycle_start(nframes);
+
        if (synced_to_jack() && waiting_to_start) {
                if ( _engine.transport_state() == AudioEngine::TransportRolling) {
                        actually_start_transport ();
@@ -54,18 +59,22 @@ Session::process (jack_nframes_t nframes)
        }
 
        if (non_realtime_work_pending()) {
-               if (atomic_read (&butler_should_do_transport_work) == 0) {
+               if (g_atomic_int_get (&butler_should_do_transport_work) == 0) {
                        post_transport ();
                } 
        } 
        
        (this->*process_function) (nframes);
+       
+       MIDI::Manager::instance()->cycle_end();
+       
+       //cerr << "CYCLE END " << _transport_frame << "-----------------------" << endl;
 }
 
 void
 Session::prepare_diskstreams ()
 {
-       for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
+       for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) {
                (*i)->prepare ();
        }
 }
@@ -85,7 +94,7 @@ Session::no_roll (jack_nframes_t nframes, jack_nframes_t offset)
           this is really bad ...
        */
 
-       if (atomic_read (&processing_prohibited)) {
+       if (g_atomic_int_get (&processing_prohibited)) {
                for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
                        (*i)->silence (nframes, offset);
                }
@@ -102,7 +111,7 @@ Session::no_roll (jack_nframes_t nframes, jack_nframes_t offset)
                
                if ((*i)->no_roll (nframes, _transport_frame, end_frame, offset, non_realtime_work_pending(), 
                                   actively_recording(), declick)) {
-                       error << compose(_("Session: error in no roll for %1"), (*i)->name()) << endmsg;
+                       error << string_compose(_("Session: error in no roll for %1"), (*i)->name()) << endmsg;
                        ret = -1;
                        break;
                }
@@ -137,12 +146,12 @@ Session::process_routes (jack_nframes_t nframes, jack_nframes_t offset)
 
                if ((ret = (*i)->roll (nframes, _transport_frame, _transport_frame + nframes, offset, declick, record_active, rec_monitors)) < 0) {
 
-                       /* we have to do this here. Route::roll() for an AudioTrack will have called DiskStream::process(),
-                          and the DS will expect DiskStream::commit() to be called. but we're aborting from that
+                       /* we have to do this here. Route::roll() for an AudioTrack will have called AudioDiskstream::process(),
+                          and the DS will expect AudioDiskstream::commit() to be called. but we're aborting from that
                           call path, so make sure we release any outstanding locks here before we return failure.
                        */
 
-                       for (DiskStreamList::iterator ids = diskstreams.begin(); ids != diskstreams.end(); ++ids) {
+                       for (AudioDiskstreamList::iterator ids = audio_diskstreams.begin(); ids != audio_diskstreams.end(); ++ids) {
                                (*ids)->recover ();
                        }
 
@@ -176,12 +185,12 @@ Session::silent_process_routes (jack_nframes_t nframes, jack_nframes_t offset)
 
                if ((ret = (*i)->silent_roll (nframes, _transport_frame, _transport_frame + nframes, offset, record_active, rec_monitors)) < 0) {
                        
-                       /* we have to do this here. Route::roll() for an AudioTrack will have called DiskStream::process(),
-                          and the DS will expect DiskStream::commit() to be called. but we're aborting from that
+                       /* we have to do this here. Route::roll() for an AudioTrack will have called AudioDiskstream::process(),
+                          and the DS will expect AudioDiskstream::commit() to be called. but we're aborting from that
                           call path, so make sure we release any outstanding locks here before we return failure.
                        */
 
-                       for (DiskStreamList::iterator ids = diskstreams.begin(); ids != diskstreams.end(); ++ids) {
+                       for (AudioDiskstreamList::iterator ids = audio_diskstreams.begin(); ids != audio_diskstreams.end(); ++ids) {
                                (*ids)->recover ();
                        }
 
@@ -200,7 +209,7 @@ Session::commit_diskstreams (jack_nframes_t nframes, bool &needs_butler)
        float pworst = 1.0f;
        float cworst = 1.0f;
 
-       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()) {
                        continue;
@@ -222,31 +231,32 @@ Session::commit_diskstreams (jack_nframes_t nframes, bool &needs_butler)
                cworst = min (cworst, (*i)->capture_buffer_load());
        }
 
-       uint32_t pmin = atomic_read (&_playback_load);
-       uint32_t pminold = atomic_read (&_playback_load_min);
-       uint32_t cmin = atomic_read (&_capture_load);
-       uint32_t cminold = atomic_read (&_capture_load_min);
+       uint32_t pmin = g_atomic_int_get (&_playback_load);
+       uint32_t pminold = g_atomic_int_get (&_playback_load_min);
+       uint32_t cmin = g_atomic_int_get (&_capture_load);
+       uint32_t cminold = g_atomic_int_get (&_capture_load_min);
 
-       atomic_set (&_playback_load, (uint32_t) floor (pworst * 100.0f));
-       atomic_set (&_capture_load, (uint32_t) floor (cworst * 100.0f));
-       atomic_set (&_playback_load_min, min (pmin, pminold));
-       atomic_set (&_capture_load_min, min (cmin, cminold));
+       g_atomic_int_set (&_playback_load, (uint32_t) floor (pworst * 100.0f));
+       g_atomic_int_set (&_capture_load, (uint32_t) floor (cworst * 100.0f));
+       g_atomic_int_set (&_playback_load_min, min (pmin, pminold));
+       g_atomic_int_set (&_capture_load_min, min (cmin, cminold));
 
        if (actively_recording()) {
                set_dirty();
        }
 }
 
+
 void
 Session::process_with_events (jack_nframes_t nframes)
 {
-       Event* ev;
+       Event*         ev;
        jack_nframes_t this_nframes;
        jack_nframes_t end_frame;
        jack_nframes_t offset;
-       bool session_needs_butler = false;
        jack_nframes_t stop_limit;
        long           frames_moved;
+       bool           session_needs_butler = false;
 
        if (auditioner) {
                auditioner->silence (nframes, 0);
@@ -267,11 +277,19 @@ Session::process_with_events (jack_nframes_t nframes)
                process_event (ev);
        }
 
+       /* Events caused a transport change, send an MTC Full Frame (SMPTE) message.
+        * This is sent whether rolling or not, to give slaves an idea of ardour time
+        * on locates (and allow slow slaves to position and prepare for rolling)
+        */
+       if (_send_smpte_update) {
+               send_full_time_code(nframes);
+       }
+
        if (!process_can_proceed()) {
                no_roll (nframes, 0);
                return;
        }
-               
+
        if (events.empty() || next_event == events.end()) {
                process_without_events (nframes);
                return;
@@ -280,11 +298,13 @@ Session::process_with_events (jack_nframes_t nframes)
        end_frame = _transport_frame + nframes;
 
        {
-               TentativeLockMonitor rm (route_lock, __LINE__, __FILE__);
+               Glib::RWLock::ReaderLock rm (route_lock, Glib::TRY_LOCK);
+               Glib::RWLock::ReaderLock dsm (diskstream_lock, Glib::TRY_LOCK);
+               
                Event* this_event;
                Events::iterator the_next_one;
 
-               if (!rm.locked() || (post_transport_work & (PostTransportLocate|PostTransportStop))) {
+               if (!rm.locked() || !dsm.locked() || (post_transport_work & (PostTransportLocate|PostTransportStop))) {
                        no_roll (nframes, 0);
                        return;
                }
@@ -299,6 +319,8 @@ Session::process_with_events (jack_nframes_t nframes)
                        no_roll (nframes, 0);
                        return;
                }
+       
+               send_midi_time_code_for_cycle(nframes);
 
                if (actively_recording()) {
                        stop_limit = max_frames;
@@ -398,17 +420,9 @@ Session::process_with_events (jack_nframes_t nframes)
 
        } /* implicit release of route lock */
 
-
-       if (session_needs_butler) {
+       if (session_needs_butler)
                summon_butler ();
-       } 
-       
-       if (!_engine.freewheeling() && send_mtc) {
-               send_midi_time_code_in_another_thread ();
-       }
-
-       return;
-}              
+}
 
 void
 Session::reset_slave_state ()
@@ -419,6 +433,18 @@ Session::reset_slave_state ()
        slave_state = Stopped;
 }
 
+bool
+Session::transport_locked () const
+{
+       Slave* sl = _slave;
+
+       if (!locate_pending() && ((_slave_type == None) || (sl && sl->ok() && sl->locked()))) {
+               return true;
+       }
+
+       return false;
+}
+
 bool
 Session::follow_slave (jack_nframes_t nframes, jack_nframes_t offset)
 {
@@ -543,15 +569,17 @@ Session::follow_slave (jack_nframes_t nframes, jack_nframes_t offset)
                if (slave_state == Waiting) {
 
                        // cerr << "waiting at " << slave_transport_frame << endl;
-
-                       if (slave_transport_frame >= slave_wait_end) {
+                       Glib::RWLock::ReaderLock dsm (diskstream_lock, Glib::TRY_LOCK);
+                       
+                       if (dsm.locked() && slave_transport_frame >= slave_wait_end) {
                                // cerr << "\tstart at " << _transport_frame << endl;
+
                                slave_state = Running;
 
                                bool ok = true;
                                jack_nframes_t frame_delta = slave_transport_frame - _transport_frame;
                                
-                               for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
+                               for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) {
                                        if (!(*i)->can_internal_playback_seek (frame_delta)) {
                                                ok = false;
                                                break;
@@ -559,7 +587,7 @@ Session::follow_slave (jack_nframes_t nframes, jack_nframes_t offset)
                                }
 
                                if (ok) {
-                                       for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
+                                       for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) {
                                                (*i)->internal_playback_seek (frame_delta);
                                        }
                                        _transport_frame += frame_delta;
@@ -662,7 +690,13 @@ Session::follow_slave (jack_nframes_t nframes, jack_nframes_t offset)
                */
 
                bool need_butler;
+               
+               Glib::RWLock::ReaderLock dsm (diskstream_lock, Glib::TRY_LOCK);
+               if (!dsm.locked()) {
+                       goto noroll;
+               }
 
+               
                prepare_diskstreams ();
                silent_process_routes (nframes, offset);
                commit_diskstreams (nframes, need_butler);
@@ -708,9 +742,10 @@ Session::process_without_events (jack_nframes_t nframes)
        long frames_moved;
        
        {
-               TentativeLockMonitor rm (route_lock, __LINE__, __FILE__);
+               Glib::RWLock::ReaderLock rm (route_lock, Glib::TRY_LOCK);
+               Glib::RWLock::ReaderLock dsm (diskstream_lock, Glib::TRY_LOCK);
 
-               if (!rm.locked() || (post_transport_work & (PostTransportLocate|PostTransportStop))) {
+               if (!rm.locked() || !dsm.locked() || (post_transport_work & (PostTransportLocate|PostTransportStop))) {
                        no_roll (nframes, 0);
                        return;
                }
@@ -725,6 +760,8 @@ Session::process_without_events (jack_nframes_t nframes)
                        no_roll (nframes, 0);
                        return;
                }
+       
+               send_midi_time_code_for_cycle(nframes);
                
                if (actively_recording()) {
                        stop_limit = max_frames;
@@ -765,21 +802,14 @@ Session::process_without_events (jack_nframes_t nframes)
 
        } /* implicit release of route lock */
 
-       if (session_needs_butler) {
+       if (session_needs_butler)
                summon_butler ();
-       } 
-       
-       if (!_engine.freewheeling() && send_mtc) {
-               send_midi_time_code_in_another_thread ();
-       }
-
-       return;
-}              
+}
 
 void
 Session::process_audition (jack_nframes_t nframes)
 {
-       TentativeLockMonitor rm (route_lock, __LINE__, __FILE__);
+       Glib::RWLock::ReaderLock rm (route_lock, Glib::TRY_LOCK);
        Event* ev;
 
        if (rm.locked()) {