tweaks to be ready for more information timecode display in Timecode clock mode
[ardour.git] / libs / ardour / session_transport.cc
index 20ac7375759cac2150da73433ac5c8c3b287dbca..6141716301c23615e5fb8db2331b50dbcf8c0386 100644 (file)
@@ -99,14 +99,16 @@ Session::request_sync_source (Slave* new_slave)
        _was_seamless = seamless;
 
        ev->slave = new_slave;
+       DEBUG_TRACE (DEBUG::Slave, "sent request for new slave\n");
        queue_event (ev);
 }
 
 void
-Session::request_transport_speed (double speed)
+Session::request_transport_speed (double speed, bool as_default)
 {
        SessionEvent* ev = new SessionEvent (SessionEvent::SetTransportSpeed, SessionEvent::Add, SessionEvent::Immediate, 0, speed);
-       DEBUG_TRACE (DEBUG::Transport, string_compose ("Request transport speed = %1\n", speed));
+       ev->third_yes_or_no = true;
+       DEBUG_TRACE (DEBUG::Transport, string_compose ("Request transport speed = %1 as default = %2\n", speed, as_default));
        queue_event (ev);
 }
 
@@ -115,13 +117,13 @@ Session::request_transport_speed (double speed)
  *  be used by callers who are varying transport speed but don't ever want to stop it.
  */
 void
-Session::request_transport_speed_nonzero (double speed)
+Session::request_transport_speed_nonzero (double speed, bool as_default)
 {
        if (speed == 0) {
                speed = DBL_EPSILON;
        }
 
-       request_transport_speed (speed);
+       request_transport_speed (speed, as_default);
 }
 
 void
@@ -298,8 +300,8 @@ Session::butler_transport_work ()
                        if (tr) {
                                tr->adjust_playback_buffering ();
                                /* and refill those buffers ... */
-                               tr->non_realtime_locate (_transport_frame);
                        }
+                       (*i)->non_realtime_locate (_transport_frame);
                }
 
        }
@@ -343,10 +345,8 @@ Session::butler_transport_work ()
                if (!(ptw & PostTransportLocate)) {
 
                        for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
-                               boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
-                               if (tr && !tr->hidden()) {
-                                       tr->non_realtime_locate (_transport_frame);
-                               }
+                               (*i)->non_realtime_locate (_transport_frame);
+
                                if (on_entry != g_atomic_int_get (&_butler->should_do_transport_work)) {
                                        /* new request, stop seeking, and start again */
                                        g_atomic_int_dec_and_test (&_butler->should_do_transport_work);
@@ -419,10 +419,7 @@ Session::non_realtime_locate ()
 {
        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->non_realtime_locate (_transport_frame);
-               }
+               (*i)->non_realtime_locate (_transport_frame);
        }
 
        /* XXX: it would be nice to generate the new clicks here (in the non-RT thread)
@@ -600,10 +597,7 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished)
        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()));
-               boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
-               if (tr && !tr->hidden()) {
-                       tr->non_realtime_locate (_transport_frame);
-               }
+               (*i)->non_realtime_locate (_transport_frame);
 
                if (on_entry != g_atomic_int_get (&_butler->should_do_transport_work)) {
                        finished = false;
@@ -645,14 +639,19 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished)
        }
 
        PositionChanged (_transport_frame); /* EMIT SIGNAL */
+       DEBUG_TRACE (DEBUG::Transport, string_compose ("send TSC with speed = %1\n", _transport_speed));
        TransportStateChange (); /* EMIT SIGNAL */
 
        /* and start it up again if relevant */
 
        if ((ptw & PostTransportLocate) && !config.get_external_sync() && pending_locate_roll) {
                request_transport_speed (1.0);
-               pending_locate_roll = false;
        }
+
+       /* Even if we didn't do a pending locate roll this time, we don't want it hanging
+          around for next time.
+       */
+       pending_locate_roll = false;
 }
 
 void
@@ -773,6 +772,7 @@ Session::set_play_loop (bool yn)
                unset_play_loop ();
        }
 
+       DEBUG_TRACE (DEBUG::Transport, string_compose ("send TSC2 with speed = %1\n", _transport_speed));
        TransportStateChange ();
 }
 void
@@ -797,6 +797,14 @@ Session::start_locate (framepos_t target_frame, bool with_roll, bool with_flush,
 
                if (target_frame != pos) {
 
+                       if (config.get_jack_time_master()) {
+                               /* actually locate now, since otherwise jack_timebase_callback
+                                  will use the incorrect _transport_frame and report an old
+                                  and incorrect time to Jack transport
+                               */
+                               locate (target_frame, with_roll, with_flush, with_loop, force);
+                       }
+
                        /* tell JACK to change transport position, and we will
                           follow along later in ::follow_slave()
                        */
@@ -847,7 +855,7 @@ Session::locate (framepos_t target_frame, bool with_roll, bool with_flush, bool
         * though, is all the housekeeping that is associated with non-linear
         * changes in the value of _transport_frame. 
         */
-        
+
        if (actively_recording() && !for_seamless_loop) {
                return;
        }
@@ -879,6 +887,7 @@ Session::locate (framepos_t target_frame, bool with_roll, bool with_flush, bool
        // Update Timecode time
        // [DR] FIXME: find out exactly where this should go below
        _transport_frame = target_frame;
+       _last_roll_or_reversal_location = target_frame;
        timecode_time(_transport_frame, transmitting_timecode_time);
        outbound_mtc_timecode_frame = _transport_frame;
        next_quarter_frame_to_send = 0;
@@ -917,7 +926,7 @@ Session::locate (framepos_t target_frame, bool with_roll, bool with_flush, bool
 
                /* this is functionally what clear_clicks() does but with a tentative lock */
 
-               Glib::RWLock::WriterLock clickm (click_lock, Glib::TRY_LOCK);
+               Glib::Threads::RWLock::WriterLock clickm (click_lock, Glib::Threads::TRY_LOCK);
 
                if (clickm.locked()) {
 
@@ -995,17 +1004,22 @@ Session::locate (framepos_t target_frame, bool with_roll, bool with_flush, bool
  *  @param speed New speed
  */
 void
-Session::set_transport_speed (double speed, bool abort, bool clear_state)
+Session::set_transport_speed (double speed, bool abort, bool clear_state, bool as_default)
 {
-       DEBUG_TRACE (DEBUG::Transport, string_compose ("@ %5 Set transport speed to %1, abort = %2 clear_state = %3, current = %4\n", 
-                                                      speed, abort, clear_state, _transport_speed, _transport_frame));
+       DEBUG_TRACE (DEBUG::Transport, string_compose ("@ %5 Set transport speed to %1, abort = %2 clear_state = %3, current = %4 as_default %6\n", 
+                                                      speed, abort, clear_state, _transport_speed, _transport_frame, as_default));
 
        if (_transport_speed == speed) {
+               if (as_default && speed == 0.0) { // => reset default transport speed. hacky or what?
+                       _default_transport_speed = 1.0;
+               }
                return;
        }
 
        if (actively_recording() && speed != 1.0 && speed != 0.0) {
                /* no varispeed during recording */
+               DEBUG_TRACE (DEBUG::Transport, string_compose ("No varispeed during recording cur_speed %1, frame %2\n", 
+                                                      _transport_speed, _transport_frame));
                return;
        }
 
@@ -1098,6 +1112,10 @@ Session::set_transport_speed (double speed, bool abort, bool clear_state)
                _last_transport_speed = _transport_speed;
                _transport_speed = speed;
 
+               if (as_default) {
+                       _default_transport_speed = speed;
+               }
+
                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);
@@ -1111,6 +1129,7 @@ Session::set_transport_speed (double speed, bool abort, bool clear_state)
                        _butler->schedule_transport_work ();
                }
 
+               DEBUG_TRACE (DEBUG::Transport, string_compose ("send TSC3 with speed = %1\n", _transport_speed));
                TransportStateChange (); /* EMIT SIGNAL */
        }
 }
@@ -1213,7 +1232,7 @@ Session::start_transport ()
 
        transport_sub_state |= PendingDeclickIn;
 
-       _transport_speed = 1.0;
+       _transport_speed = _default_transport_speed;
        _target_transport_speed = _transport_speed;
 
        boost::shared_ptr<RouteList> rl = routes.reader();
@@ -1222,7 +1241,6 @@ Session::start_transport ()
                if (tr) {
                        tr->realtime_set_speed (tr->speed(), true);
                }
-               (*i)->automation_snapshot (_transport_frame, true);
        }
 
        if (!_engine.freewheeling()) {
@@ -1233,6 +1251,7 @@ Session::start_transport ()
                }
        }
 
+       DEBUG_TRACE (DEBUG::Transport, string_compose ("send TSC4 with speed = %1\n", _transport_speed));
        TransportStateChange (); /* EMIT SIGNAL */
 }
 
@@ -1305,6 +1324,8 @@ Session::use_sync_source (Slave* new_slave)
        delete _slave;
        _slave = new_slave;
 
+       DEBUG_TRACE (DEBUG::Slave, string_compose ("set new slave to %1\n", _slave));
+
        send_full_time_code (_transport_frame);
 
        boost::shared_ptr<RouteList> rl = routes.reader();
@@ -1354,6 +1375,24 @@ Session::switch_to_sync_source (SyncSource src)
                }
                break;
 
+       case LTC:
+#ifdef HAVE_LTC
+               if (_slave && dynamic_cast<LTC_Slave*>(_slave)) {
+                       return;
+               }
+
+               try {
+                       new_slave = new LTC_Slave (*this);
+               }
+
+               catch (failed_constructor& err) {
+                       return;
+               }
+#else
+               return;
+#endif
+               break;
+
        case MIDIClock:
                if (_slave && dynamic_cast<MIDIClock_Slave*>(_slave)) {
                        return;
@@ -1481,6 +1520,7 @@ Session::set_play_range (list<AudioRange>& range, bool leave_rolling)
        ev = new SessionEvent (SessionEvent::LocateRoll, SessionEvent::Add, SessionEvent::Immediate, range.front().start, 0.0f, false);
        merge_event (ev);
 
+       DEBUG_TRACE (DEBUG::Transport, string_compose ("send TSC5 with speed = %1\n", _transport_speed));
        TransportStateChange ();
 }
 
@@ -1523,6 +1563,7 @@ Session::engine_halted ()
        non_realtime_stop (false, 0, ignored);
        transport_sub_state = 0;
 
+       DEBUG_TRACE (DEBUG::Transport, string_compose ("send TSC6 with speed = %1\n", _transport_speed));
        TransportStateChange (); /* EMIT SIGNAL */
 }