Fix importing to a fixed-point format with resampling
[ardour.git] / libs / ardour / transport_master.cc
index 4ebdbbf50bccacbd4198e235aa0fe7bd4ca31f3e..2564f87c5dd55e0717299696aaf12fbc4863b4e8 100644 (file)
@@ -20,9 +20,9 @@
 #include <vector>
 
 #include "pbd/debug.h"
-#include "pbd/i18n.h"
 
 #include "ardour/audioengine.h"
+#include "ardour/debug.h"
 #include "ardour/midi_port.h"
 #include "ardour/session.h"
 #include "ardour/transport_master.h"
@@ -30,6 +30,8 @@
 #include "ardour/types_convert.h"
 #include "ardour/utils.h"
 
+#include "pbd/i18n.h"
+
 namespace ARDOUR {
        namespace Properties {
                PBD::PropertyDescriptor<bool> fr2997;
@@ -54,6 +56,8 @@ TransportMaster::make_property_quarks ()
        DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for collect = %1\n", Properties::collect.property_id));
        Properties::connected.property_id = g_quark_from_static_string (X_("connected"));
        DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for connected = %1\n", Properties::connected.property_id));
+       Properties::allowed_transport_requests.property_id = g_quark_from_static_string (X_("allowed_transport_requests"));
+       DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for allowed_transport_requests = %1\n", Properties::allowed_transport_requests.property_id));
 }
 
 const std::string TransportMaster::state_node_name = X_("TransportMaster");
@@ -64,6 +68,7 @@ TransportMaster::TransportMaster (SyncSource t, std::string const & name)
        , _session (0)
        , _current_delta (0)
        , _pending_collect (true)
+       , _removeable (false)
        , _request_mask (Properties::allowed_transport_requests, TransportRequestType (0))
        , _locked (Properties::locked, false)
        , _sclock_synced (Properties::sclock_synced, false)
@@ -78,7 +83,59 @@ TransportMaster::TransportMaster (SyncSource t, std::string const & name)
 
 TransportMaster::~TransportMaster()
 {
-       delete _session;
+}
+
+bool
+TransportMaster::speed_and_position (double& speed, samplepos_t& pos, samplepos_t& lp, samplepos_t& when, samplepos_t now)
+{
+       if (!_collect) {
+               return false;
+       }
+
+       SafeTime last;
+       current.safe_read (last);
+
+       if (last.timestamp == 0) {
+               return false;
+       }
+
+       if (last.timestamp && now > last.timestamp && now - last.timestamp > (2.0 * update_interval())) {
+               /* no timecode for two cycles - conclude that it's stopped */
+
+               if (!Config->get_transport_masters_just_roll_when_sync_lost()) {
+                       speed = 0;
+                       pos = last.position;
+                       lp = last.position;
+                       when = last.timestamp;
+                       _current_delta = 0;
+                       // queue_reset (false);
+                       DEBUG_TRACE (DEBUG::Slave, string_compose ("%1 not seen since %2 vs %3 (%4) with seekahead = %5 reset pending, pos = %6\n", name(), last.timestamp, now, (now - last.timestamp), update_interval(), pos));
+                       return false;
+               }
+       }
+
+       lp = last.position;
+       when = last.timestamp;
+       speed = last.speed;
+       pos   = last.position + (now - last.timestamp) * last.speed;
+
+       DEBUG_TRACE (DEBUG::Slave, string_compose ("%1: speed_and_position tme: %2 pos: %3 spd: %4\n", name(), last.timestamp, last.position, last.speed));
+
+       lp = last.position;
+       when = last.timestamp;
+       speed = last.speed;
+
+       /* provide a .1% deadzone to lock the speed */
+       if (fabs (speed - 1.0) <= 0.001) {
+               speed = 1.0;
+       }
+
+       pos = last.position + (now - last.timestamp) * speed;
+
+       DEBUG_TRACE (DEBUG::Slave, string_compose ("%1 sync spd: %2 pos: %3 | last-pos: %4 | elapsed: %5\n",
+                                                  name(), speed, pos, last.position, (now - last.timestamp)));
+
+       return true;
 }
 
 void
@@ -102,7 +159,7 @@ TransportMaster::set_name (std::string const & str)
 {
        if (_name != str) {
                _name = str;
-               PropertyChange (Properties::name);
+               PropertyChanged (Properties::name);
        }
 }
 
@@ -167,7 +224,16 @@ TransportMaster::check_collect()
 void
 TransportMaster::set_collect (bool yn)
 {
-       _pending_collect = yn;
+       /* theoretical race condition */
+
+       if (_connected) {
+               _pending_collect = yn;
+       } else {
+               if (_collect != yn) {
+                       _pending_collect = _collect = yn;
+                       PropertyChanged (Properties::collect);
+               }
+       }
 }
 
 void
@@ -219,6 +285,7 @@ TransportMaster::get_state ()
 {
        XMLNode* node = new XMLNode (state_node_name);
        node->set_property (X_("type"), _type);
+       node->set_property (X_("removeable"), _removeable);
 
        add_properties (*node);
 
@@ -263,6 +330,7 @@ TransportMaster::factory (XMLNode const & node)
 
        SyncSource type;
        std::string name;
+       bool removeable;
 
        if (!node.get_property (X_("type"), type)) {
                return boost::shared_ptr<TransportMaster>();
@@ -272,28 +340,95 @@ TransportMaster::factory (XMLNode const & node)
                return boost::shared_ptr<TransportMaster>();
        }
 
-       return factory (type, name);
+       if (!node.get_property (X_("removeable"), removeable)) {
+               /* development versions of 6.0 didn't have this property for a
+                  while. Any TM listed in XML at that time was non-removeable
+               */
+               removeable = false;
+       }
+
+       DEBUG_TRACE (DEBUG::Slave, string_compose ("xml-construct %1 name %2 removeable %3\n", enum_2_string (type), name, removeable));
+
+       return factory (type, name, removeable);
 }
 
 boost::shared_ptr<TransportMaster>
-TransportMaster::factory (SyncSource type, std::string const& name)
+TransportMaster::factory (SyncSource type, std::string const& name, bool removeable)
 {
        /* XXX need to count existing sources of a given type */
 
+       boost::shared_ptr<TransportMaster> tm;
+
+       DEBUG_TRACE (DEBUG::Slave, string_compose ("factory-construct %1 name %2 removeable %3\n", enum_2_string (type), name, removeable));
+
        switch (type) {
        case MTC:
-               return boost::shared_ptr<TransportMaster> (new MTC_TransportMaster (sync_source_to_string (type)));
+               tm.reset (new MTC_TransportMaster (name));
+               break;
        case LTC:
-               return boost::shared_ptr<TransportMaster> (new LTC_TransportMaster (sync_source_to_string (type)));
+               tm.reset (new LTC_TransportMaster (name));
+               break;
        case MIDIClock:
-               return boost::shared_ptr<TransportMaster> (new MIDIClock_TransportMaster (sync_source_to_string (type)));
+               tm.reset (new MIDIClock_TransportMaster (name));
+               break;
        case Engine:
-               return boost::shared_ptr<TransportMaster> (new Engine_TransportMaster (*AudioEngine::instance()));
+               tm.reset (new Engine_TransportMaster (*AudioEngine::instance()));
+               break;
        default:
                break;
        }
 
-       return boost::shared_ptr<TransportMaster>();
+       if (tm) {
+               tm->set_removeable (removeable);
+       }
+
+       return tm;
+}
+
+/** @param sh Return a short version of the string */
+std::string
+TransportMaster::display_name (bool sh) const
+{
+
+       switch (_type) {
+       case Engine:
+               /* no other backends offer sync for now ... deal with this if we
+                * ever have to.
+                */
+               return S_("SyncSource|JACK");
+
+       case MTC:
+               if (sh) {
+                       if (name().length() <= 4) {
+                               return name();
+                       }
+                       return S_("SyncSource|MTC");
+               } else {
+                       return name();
+               }
+
+       case MIDIClock:
+               if (sh) {
+                       if (name().length() <= 4) {
+                               return name();
+                       }
+                       return S_("SyncSource|M-Clk");
+               } else {
+                       return name();
+               }
+
+       case LTC:
+               if (sh) {
+                       if (name().length() <= 4) {
+                               return name();
+                       }
+                       return S_("SyncSource|LTC");
+               } else {
+                       return name();
+               }
+       }
+       /* GRRRR .... stupid, stupid gcc - you can't get here from there, all enum values are handled */
+       return S_("SyncSource|JACK");
 }
 
 boost::shared_ptr<Port>
@@ -347,3 +482,4 @@ TimecodeTransportMaster::set_fr2997 (bool yn)
                PropertyChanged (Properties::fr2997);
        }
 }
+