sort of no-op ... remove debug output ... just basically put it in git so that i...
[ardour.git] / libs / ardour / session_transport.cc
index 4818cfaab3f7f054b65afc1c3a036d8e6add445b..f09f3ac2538d2e2bc60571ac646901472d793fbb 100644 (file)
@@ -41,6 +41,7 @@
 #include "ardour/butler.h"
 #include "ardour/click.h"
 #include "ardour/debug.h"
+#include "ardour/disk_reader.h"
 #include "ardour/location.h"
 #include "ardour/profile.h"
 #include "ardour/scene_changer.h"
@@ -48,6 +49,8 @@
 #include "ardour/slave.h"
 #include "ardour/tempo.h"
 #include "ardour/operations.h"
+#include "ardour/vca.h"
+#include "ardour/vca_manager.h"
 
 #include "pbd/i18n.h"
 
@@ -74,15 +77,6 @@ Session::add_post_transport_work (PostTransportWork ptw)
        error << "Could not set post transport work! Crazy thread madness, call the programmers" << endmsg;
 }
 
-void
-Session::request_input_change_handling ()
-{
-       if (!(_state_of_the_state & (InitialConnecting|Deletion))) {
-               SessionEvent* ev = new SessionEvent (SessionEvent::InputConfigurationChange, SessionEvent::Add, SessionEvent::Immediate, 0, 0.0);
-               queue_event (ev);
-       }
-}
-
 void
 Session::request_sync_source (Slave* new_slave)
 {
@@ -130,14 +124,6 @@ Session::request_transport_speed_nonzero (double speed, bool as_default)
        request_transport_speed (speed, as_default);
 }
 
-void
-Session::request_track_speed (Track* tr, double speed)
-{
-       SessionEvent* ev = new SessionEvent (SessionEvent::SetTrackSpeed, SessionEvent::Add, SessionEvent::Immediate, 0, speed);
-       ev->set_ptr (tr);
-       queue_event (ev);
-}
-
 void
 Session::request_stop (bool abort, bool clear_state)
 {
@@ -217,6 +203,20 @@ Session::request_preroll_record_trim (framepos_t rec_in, framecnt_t preroll)
        set_requested_return_frame (rec_in);
 }
 
+void
+Session::request_count_in_record ()
+{
+       if (actively_recording ()) {
+               return;
+       }
+       if (transport_rolling()) {
+               return;
+       }
+       maybe_enable_record ();
+       _count_in_once = true;
+       request_transport_speed (1.0, true);
+}
+
 void
 Session::request_play_loop (bool yn, bool change_transport_roll)
 {
@@ -430,12 +430,6 @@ Session::butler_transport_work ()
        }
 
        if (ptw & PostTransportAdjustPlaybackBuffering) {
-               /* non_realtime_locate() calls Automatable::transport_located()
-                * for every route. This eventually calls
-                * ARDOUR::AutomationList::state () which has a LocaleGuard,
-                * and would switch locales forth/back every time.
-                */
-               LocaleGuard lg;
                for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
                        boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
                        if (tr) {
@@ -444,7 +438,10 @@ Session::butler_transport_work ()
                        }
                        (*i)->non_realtime_locate (_transport_frame);
                }
-
+               VCAList v = _vca_manager->vcas ();
+               for (VCAList::const_iterator i = v.begin(); i != v.end(); ++i) {
+                       (*i)->non_realtime_locate (_transport_frame);
+               }
        }
 
        if (ptw & PostTransportAdjustCaptureBuffering) {
@@ -462,15 +459,6 @@ Session::butler_transport_work ()
                }
        }
 
-       if (ptw & PostTransportInputChange) {
-               for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
-                       boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
-                       if (tr) {
-                               tr->non_realtime_input_change ();
-                       }
-               }
-       }
-
        if (ptw & PostTransportSpeed) {
                non_realtime_set_speed ();
        }
@@ -484,7 +472,6 @@ Session::butler_transport_work ()
                /* don't seek if locate will take care of that in non_realtime_stop() */
 
                if (!(ptw & PostTransportLocate)) {
-                       LocaleGuard lg; // see note for non_realtime_locate() above
                        for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
                                (*i)->non_realtime_locate (_transport_frame);
 
@@ -494,6 +481,10 @@ Session::butler_transport_work ()
                                        goto restart;
                                }
                        }
+                       VCAList v = _vca_manager->vcas ();
+                       for (VCAList::const_iterator i = v.begin(); i != v.end(); ++i) {
+                               (*i)->non_realtime_locate (_transport_frame);
+                       }
                }
        }
 
@@ -524,8 +515,7 @@ Session::butler_transport_work ()
 
        g_atomic_int_dec_and_test (&_butler->should_do_transport_work);
 
-       DEBUG_TRACE (DEBUG::Transport, string_compose (X_("Butler transport work all done after %1 usecs\n"), g_get_monotonic_time() - before));
-       DEBUG_TRACE (DEBUG::Transport, X_(string_compose ("Frame %1\n", _transport_frame)));
+       DEBUG_TRACE (DEBUG::Transport, string_compose (X_("Butler transport work all done after %1 usecs @ %2 trw = %3\n"), g_get_monotonic_time() - before, _transport_frame, _butler->transport_work_requested()));
 }
 
 void
@@ -535,7 +525,7 @@ Session::non_realtime_set_speed ()
        for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
                boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
                if (tr) {
-                       tr->non_realtime_set_speed ();
+                       tr->non_realtime_speed_change ();
                }
        }
 }
@@ -593,14 +583,46 @@ Session::non_realtime_locate ()
        }
 
 
+       microseconds_t begin = get_microseconds ();
+       framepos_t tf;
+
        {
-               LocaleGuard lg; // see note for non_realtime_locate() above
                boost::shared_ptr<RouteList> rl = routes.reader();
+
+         restart:
+               gint sc = g_atomic_int_get (&_seek_counter);
+               tf = _transport_frame;
+
+               cerr << "\n\n >>> START Non-RT locate on routes to " << tf << " counter = " << sc << "\n\n";
+
                for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
-                       (*i)->non_realtime_locate (_transport_frame);
+                       (*i)->non_realtime_locate (tf);
+                       //::usleep (250000);
+                       cerr << "\t\tcounter after track: " << g_atomic_int_get (&_seek_counter) << endl;
+                       if (sc != g_atomic_int_get (&_seek_counter)) {
+                               cerr << "\n\n RESTART locate, new seek delivered\n";
+                               goto restart;
+                       }
                }
+
+               cerr << "\n\n <<< DONE Non-RT locate on routes\n\n";
        }
 
+       {
+               /* VCAs are quick to locate because they have no data (except
+                  automation) associated with them. Don't bother with a
+                  restart mechanism here, but do use the same transport frame
+                  that the Routes used.
+               */
+               VCAList v = _vca_manager->vcas ();
+               for (VCAList::const_iterator i = v.begin(); i != v.end(); ++i) {
+                       (*i)->non_realtime_locate (tf);
+               }
+       }
+
+       microseconds_t end = get_microseconds ();
+       cerr << "Locate took " << setprecision (3) << ((end - begin) /1000000.0) << " secs\n";
+
        _scene_changer->locate (_transport_frame);
 
        /* XXX: it would be nice to generate the new clicks here (in the non-RT thread)
@@ -786,9 +808,15 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished)
 
        if (_engine.running()) {
                PostTransportWork ptw = post_transport_work ();
+
                for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
-                       (*i)->nonrealtime_handle_transport_stopped (abort, (ptw & PostTransportLocate), (!(ptw & PostTransportLocate) || pending_locate_flush));
+                       (*i)->non_realtime_transport_stop (_transport_frame, !(ptw & PostTransportLocate) || pending_locate_flush);
                }
+               VCAList v = _vca_manager->vcas ();
+               for (VCAList::const_iterator i = v.begin(); i != v.end(); ++i) {
+                       (*i)->non_realtime_transport_stop (_transport_frame, !(ptw & PostTransportLocate) || pending_locate_flush);
+               }
+
                update_latency_compensation ();
        }
 
@@ -861,7 +889,6 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished)
        /* this for() block can be put inside the previous if() and has the effect of ... ??? what */
 
        {
-               LocaleGuard lg; // see note for non_realtime_locate() above
                DEBUG_TRACE (DEBUG::Transport, X_("Butler PTW: locate\n"));
                for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
                        DEBUG_TRACE (DEBUG::Transport, string_compose ("Butler PTW: locate on %1\n", (*i)->name()));
@@ -875,6 +902,13 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished)
                }
        }
 
+       {
+               VCAList v = _vca_manager->vcas ();
+               for (VCAList::const_iterator i = v.begin(); i != v.end(); ++i) {
+                       (*i)->non_realtime_locate (_transport_frame);
+               }
+       }
+
        have_looped = false;
 
        /* don't bother with this stuff if we're disconnected from the engine,
@@ -1008,7 +1042,7 @@ Session::set_track_loop (bool yn)
 
        for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
                boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
-               if (tr && !tr->hidden()) {
+               if (tr && !tr->is_private_route()) {
                        tr->set_loop (yn ? loc : 0);
                }
        }
@@ -1214,12 +1248,18 @@ Session::locate (framepos_t target_frame, bool with_roll, bool with_flush, bool
                        pending_locate_frame = target_frame;
                        pending_locate_roll = with_roll;
                        pending_locate_flush = with_flush;
+                       cerr << "Declick scheduled ... back soon\n";
                        return;
                }
        }
 
+       cerr << "... now doing the actual locate\n";
+
        // Update Timecode time
        _transport_frame = target_frame;
+       // Bump seek counter so that any in-process locate in the butler
+       // thread(s?) can restart.
+       g_atomic_int_inc (&_seek_counter);
        _last_roll_or_reversal_location = target_frame;
        timecode_time(_transport_frame, transmitting_timecode_time);
 
@@ -1353,7 +1393,9 @@ Session::locate (framepos_t target_frame, bool with_roll, bool with_flush, bool
        }
 
        _last_roll_location = _last_roll_or_reversal_location =  _transport_frame;
-       Located (); /* EMIT SIGNAL */
+       if (!synced_to_engine () || _transport_frame == _engine.transport_frame ()) {
+               Located (); /* EMIT SIGNAL */
+       }
 }
 
 /** Set the transport speed.
@@ -1406,6 +1448,7 @@ Session::set_transport_speed (double speed, framepos_t destination_frame, bool a
                                   take care of it.
                                */
                                _play_range = false;
+                               _count_in_once = false;
                                unset_play_loop ();
                        }
                        _engine.transport_stop ();
@@ -1451,6 +1494,7 @@ Session::set_transport_speed (double speed, framepos_t destination_frame, bool a
 
                if (synced_to_engine()) {
                        _engine.transport_start ();
+                       _count_in_once = false;
                } else {
                        start_transport ();
                }
@@ -1502,7 +1546,7 @@ Session::set_transport_speed (double speed, framepos_t destination_frame, bool a
                boost::shared_ptr<RouteList> rl = routes.reader();
                for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
                        boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
-                       if (tr && tr->realtime_set_speed (tr->speed(), true)) {
+                       if (tr && tr->realtime_speed_change()) {
                                todo = PostTransportWork (todo | PostTransportSpeed);
                        }
                }
@@ -1543,6 +1587,7 @@ Session::set_transport_speed (double speed, framepos_t destination_frame, bool a
 void
 Session::stop_transport (bool abort, bool clear_state)
 {
+       _count_in_once = false;
        if (_transport_speed == 0.0f) {
                return;
        }
@@ -1665,7 +1710,7 @@ Session::start_transport ()
        for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
                boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
                if (tr) {
-                       tr->realtime_set_speed (tr->speed(), true);
+                       tr->realtime_speed_change ();
                }
        }
 
@@ -1676,7 +1721,8 @@ Session::start_transport ()
                        send_immediate_mmc (MIDI::MachineControlCommand (MIDI::MachineControl::cmdDeferredPlay));
                }
 
-               if (actively_recording() && click_data && config.get_count_in ()) {
+               if (actively_recording() && click_data && (config.get_count_in () || _count_in_once)) {
+                       _count_in_once = false;
                        /* calculate count-in duration (in audio samples)
                         * - use [fixed] tempo/meter at _transport_frame
                         * - calc duration of 1 bar + time-to-beat before or at transport_frame
@@ -1684,19 +1730,20 @@ Session::start_transport ()
                        const Tempo& tempo = _tempo_map->tempo_at_frame (_transport_frame);
                        const Meter& meter = _tempo_map->meter_at_frame (_transport_frame);
 
-                       double div = meter.divisions_per_bar ();
-                       double pulses = _tempo_map->exact_qn_at_frame (_transport_frame, 0) * div / 4.0;
-                       double beats_left = fmod (pulses, div);
+                       const double num = meter.divisions_per_bar ();
+                       const double den = meter.note_divisor ();
+                       const double barbeat = _tempo_map->exact_qn_at_frame (_transport_frame, 0) * den / (4. * num);
+                       const double bar_fract = fmod (barbeat, 1.0); // fraction of bar elapsed.
 
                        _count_in_samples = meter.frames_per_bar (tempo, _current_frame_rate);
 
-                       double dt = _count_in_samples / div;
-                       if (beats_left == 0) {
+                       double dt = _count_in_samples / num;
+                       if (bar_fract == 0) {
                                /* at bar boundary, count-in 2 bars before start. */
                                _count_in_samples *= 2;
                        } else {
                                /* beats left after full bar until roll position */
-                               _count_in_samples += meter.frames_per_grid (tempo, _current_frame_rate) * beats_left;
+                               _count_in_samples *= 1. + bar_fract;
                        }
 
                        int clickbeat = 0;
@@ -1704,7 +1751,7 @@ Session::start_transport ()
                        while (cf < _transport_frame) {
                                add_click (cf - _worst_track_latency, clickbeat == 0);
                                cf += dt;
-                               clickbeat = fmod (clickbeat + 1, div);
+                               clickbeat = fmod (clickbeat + 1, num);
                        }
                }
        }
@@ -1737,6 +1784,7 @@ Session::post_transport ()
        if (ptw & PostTransportLocate) {
 
                if (((!config.get_external_sync() && (auto_play_legal && config.get_auto_play())) && !_exporting) || (ptw & PostTransportRoll)) {
+                       _count_in_once = false;
                        start_transport ();
                } else {
                        transport_sub_state = 0;
@@ -1796,6 +1844,12 @@ Session::use_sync_source (Slave* new_slave)
        delete _slave;
        _slave = new_slave;
 
+
+       /* slave change, reset any DiskIO block on disk output because it is no
+          longer valid with a new slave.
+       */
+       DiskReader::set_no_disk_output (false);
+
        MTC_Slave* mtc_slave = dynamic_cast<MTC_Slave*>(_slave);
        if (mtc_slave) {
                mtc_slave->ActiveChanged.connect_same_thread (mtc_status_connection, boost::bind (&Session::mtc_status_changed, this, _1));
@@ -1828,8 +1882,8 @@ Session::use_sync_source (Slave* new_slave)
        boost::shared_ptr<RouteList> rl = routes.reader();
        for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
                boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
-               if (tr && !tr->hidden()) {
-                       if (tr->realtime_set_speed (tr->speed(), true)) {
+               if (tr && !tr->is_private_route()) {
+                       if (tr->realtime_speed_change()) {
                                non_rt_required = true;
                        }
                        tr->set_slaved (_slave != 0);
@@ -1921,16 +1975,6 @@ Session::switch_to_sync_source (SyncSource src)
        request_sync_source (new_slave);
 }
 
-void
-Session::set_track_speed (Track* track, double speed)
-{
-       if (track->realtime_set_speed (speed, false)) {
-               add_post_transport_work (PostTransportSpeed);
-               _butler->schedule_transport_work ();
-               set_dirty ();
-       }
-}
-
 void
 Session::unset_play_range ()
 {