#include <vector>
-#include "pbd/i18n.h"
+#include "pbd/debug.h"
#include "ardour/audioengine.h"
+#include "ardour/debug.h"
#include "ardour/midi_port.h"
#include "ardour/session.h"
#include "ardour/transport_master.h"
#include "ardour/transport_master_manager.h"
+#include "ardour/types_convert.h"
#include "ardour/utils.h"
+#include "pbd/i18n.h"
+
+namespace ARDOUR {
+ namespace Properties {
+ PBD::PropertyDescriptor<bool> fr2997;
+ PBD::PropertyDescriptor<bool> sclock_synced;
+ PBD::PropertyDescriptor<bool> collect;
+ PBD::PropertyDescriptor<bool> connected;
+ PBD::PropertyDescriptor<TransportRequestType> allowed_transport_requests;
+ }
+}
+
using namespace ARDOUR;
+using namespace PBD;
-const std::string TransportMaster::state_node_name = X_("TransportMaster");
+void
+TransportMaster::make_property_quarks ()
+{
+ Properties::fr2997.property_id = g_quark_from_static_string (X_("fr2997"));
+ DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for fr2997 = %1\n", Properties::fr2997.property_id));
+ Properties::sclock_synced.property_id = g_quark_from_static_string (X_("sclock_synced"));
+ DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for sclock_synced = %1\n", Properties::sclock_synced.property_id));
+ Properties::collect.property_id = g_quark_from_static_string (X_("collect"));
+ 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");
TransportMaster::TransportMaster (SyncSource t, std::string const & name)
: _type (t)
- , _name (name)
+ , _name (Properties::name, name)
, _session (0)
- , _connected (false)
, _current_delta (0)
- , _collect (true)
, _pending_collect (true)
- , _request_mask (TransportRequestType (0))
- , _sclock_synced (false)
+ , _removeable (false)
+ , _request_mask (Properties::allowed_transport_requests, TransportRequestType (0))
+ , _locked (Properties::locked, false)
+ , _sclock_synced (Properties::sclock_synced, false)
+ , _collect (Properties::collect, true)
+ , _connected (Properties::connected, false)
{
+ register_properties ();
+
ARDOUR::AudioEngine::instance()->PortConnectedOrDisconnected.connect_same_thread (port_connection, boost::bind (&TransportMaster::connection_handler, this, _1, _2, _3, _4, _5));
ARDOUR::AudioEngine::instance()->Running.connect_same_thread (backend_connection, boost::bind (&TransportMaster::check_backend, this));
}
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
+TransportMaster::register_properties ()
+{
+ _xml_node_name = state_node_name;
+
+ add_property (_name);
+ add_property (_locked);
+ add_property (_collect);
+ add_property (_sclock_synced);
+ add_property (_request_mask);
+
+ /* we omit _connected since it is derived from port state, and merely
+ * used for signalling
+ */
+}
+
+void
+TransportMaster::set_name (std::string const & str)
+{
+ if (_name != str) {
+ _name = str;
+ PropertyChanged (Properties::name);
+ }
}
bool
/* it's about us */
+ /* XXX technically .. if the user makes an N->1 connection to
+ * this transport master's port, this simple minded logic is
+ * not sufficient. But the user shouldn't do that ...
+ */
+
if (yn) {
_connected = true;
} else {
_connected = false;
}
+ PropertyChanged (Properties::connected);
+
return true;
}
}
}
}
- std::cerr << name() << " pc = " << _pending_collect << " c = " << _collect << std::endl;
_collect = _pending_collect;
+ PropertyChanged (Properties::collect);
}
return _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
TransportMaster::set_sample_clock_synced (bool yn)
{
- _sclock_synced = yn;
+ if (yn != _sclock_synced) {
+ _sclock_synced = yn;
+ PropertyChanged (Properties::sclock_synced);
+ }
}
void
int
TransportMaster::set_state (XMLNode const & node, int /* version */)
{
- if (!node.get_property (X_("collect"), _collect)) {
- _collect = false;
- }
-
- if (!node.get_property (X_("clock-synced"), _sclock_synced)) {
- _sclock_synced = false;
- }
+ PropertyChange what_changed;
- TimecodeTransportMaster* ttm = dynamic_cast<TimecodeTransportMaster*> (this);
- if (ttm) {
- bool val;
- node.get_property (X_("fr2997"), val);
- ttm->set_fr2997 (val);
- }
+ what_changed = set_values (node);
XMLNode* pnode = node.child (X_("Port"));
}
}
+ PropertyChanged (what_changed);
+
return 0;
}
{
XMLNode* node = new XMLNode (state_node_name);
node->set_property (X_("type"), _type);
- node->set_property (X_("name"), _name);
- node->set_property (X_("collect"), _collect);
- node->set_property (X_("clock-synced"), _sclock_synced);
+ node->set_property (X_("removeable"), _removeable);
- TimecodeTransportMaster* ttm = dynamic_cast<TimecodeTransportMaster*> (this);
- if (ttm) {
- node->set_property (X_("fr2997"), ttm->fr2997());
- }
+ add_properties (*node);
if (_port) {
std::vector<std::string> connections;
SyncSource type;
std::string name;
+ bool removeable;
if (!node.get_property (X_("type"), type)) {
return boost::shared_ptr<TransportMaster>();
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>
void
TransportMaster::set_request_mask (TransportRequestType t)
{
- _request_mask = t;
+ if (_request_mask != t) {
+ _request_mask = t;
+ PropertyChanged (Properties::allowed_transport_requests);
+ }
+}
+
+TimecodeTransportMaster::TimecodeTransportMaster (std::string const & name, SyncSource type)
+ : TransportMaster (type, name)
+ , _fr2997 (Properties::fr2997, false)
+{
+ register_properties ();
+}
+
+void
+TimecodeTransportMaster::register_properties ()
+{
+ TransportMaster::register_properties ();
+ add_property (_fr2997);
}
void
TimecodeTransportMaster::set_fr2997 (bool yn)
{
- _fr2997 = yn;
+ if (yn != _fr2997) {
+ _fr2997 = yn;
+ PropertyChanged (Properties::fr2997);
+ }
}
+