summaryrefslogtreecommitdiff
path: root/libs/ardour/mtc_slave.cc
diff options
context:
space:
mode:
Diffstat (limited to 'libs/ardour/mtc_slave.cc')
-rw-r--r--libs/ardour/mtc_slave.cc111
1 files changed, 89 insertions, 22 deletions
diff --git a/libs/ardour/mtc_slave.cc b/libs/ardour/mtc_slave.cc
index 9e566367bc..41aaaccbcf 100644
--- a/libs/ardour/mtc_slave.cc
+++ b/libs/ardour/mtc_slave.cc
@@ -41,6 +41,16 @@ using namespace sigc;
using namespace MIDI;
using namespace PBD;
+/* length (in timecode frames) of the "window" that we consider legal given receipt of
+ a given timecode position. Ardour will try to chase within this window, and will
+ stop+locate+wait+chase if timecode arrives outside of it. The window extends entirely
+ in the current direction of motion, so if any timecode arrives that is before the most
+ recently received position (and without the direction of timecode reversing too), we
+ will stop+locate+wait+chase.
+*/
+
+const int MTC_Slave::frame_tolerance = 2;
+
MTC_Slave::MTC_Slave (Session& s, MIDI::Port& p)
: session (s)
{
@@ -71,8 +81,8 @@ MTC_Slave::~MTC_Slave()
bool
MTC_Slave::give_slave_full_control_over_transport_speed() const
{
- return true; // for PiC control */
- // return false; // for Session-level computed varispeed
+ // return true; // for PiC control */
+ return false; // for Session-level computed varispeed
}
void
@@ -84,8 +94,6 @@ MTC_Slave::rebind (MIDI::Port& p)
port = &p;
- cerr << "Bind to port MTC messages\n";
-
connections.push_back (port->input()->mtc_time.connect (mem_fun (*this, &MTC_Slave::update_mtc_time)));
connections.push_back (port->input()->mtc_qtr.connect (mem_fun (*this, &MTC_Slave::update_mtc_qtr)));
connections.push_back (port->input()->mtc_status.connect (mem_fun (*this, &MTC_Slave::update_mtc_status)));
@@ -94,6 +102,8 @@ MTC_Slave::rebind (MIDI::Port& p)
void
MTC_Slave::update_mtc_qtr (Parser& /*p*/, int which_qtr, nframes_t now)
{
+ maybe_reset ();
+
DEBUG_TRACE (DEBUG::MTC, string_compose ("qtr frame %1 at %2\n", which_qtr, now));
last_inbound_frame = now;
}
@@ -102,9 +112,14 @@ void
MTC_Slave::update_mtc_time (const byte *msg, bool was_full, nframes_t now)
{
/* "now" can be zero if this is called from a context where we do not have or do not want
- to use a timestamp indicating when this MTC time was received.
+ to use a timestamp indicating when this MTC time was received. example: when we received
+ a locate command via MMC.
*/
+ if (now) {
+ maybe_reset ();
+ }
+
Timecode::Time timecode;
TimecodeFormat tc_format;
bool reset_tc = true;
@@ -174,8 +189,7 @@ MTC_Slave::update_mtc_time (const byte *msg, bool was_full, nframes_t now)
session.request_locate (mtc_frame, false);
session.request_transport_speed (0);
update_mtc_status (MIDI::MTC_Stopped);
- window_root = mtc_frame;
-
+ reset_window (mtc_frame);
reset ();
} else {
@@ -265,6 +279,12 @@ MTC_Slave::process_apparent_speed (double this_speed)
{
DEBUG_TRACE (DEBUG::MTC, string_compose ("speed cnt %1 sz %2 have %3\n", speed_accumulator_cnt, speed_accumulator_size, have_first_speed_accumulator));
+ /* clamp to an expected range */
+
+ if (this_speed > 4.0 || this_speed < -4.0) {
+ this_speed = average_speed;
+ }
+
if (speed_accumulator_cnt >= speed_accumulator_size) {
have_first_speed_accumulator = true;
speed_accumulator_cnt = 0;
@@ -385,9 +405,8 @@ MTC_Slave::speed_and_position (double& speed, nframes64_t& pos)
pos = last.position;
session.request_locate (pos, false);
session.request_transport_speed (0);
- update_mtc_status (MIDI::MTC_Stopped);
- reset();
- DEBUG_TRACE (DEBUG::MTC, "MTC not seen for 1/4 second - reset\n");
+ queue_reset ();
+ DEBUG_TRACE (DEBUG::MTC, "MTC not seen for 1/4 second - reset pending\n");
return false;
}
@@ -427,13 +446,28 @@ MTC_Slave::resolution() const
}
void
-MTC_Slave::reset ()
+MTC_Slave::queue_reset ()
{
- /* XXX massive thread safety issue here. MTC could
- be being updated as we call this. but this
- supposed to be a realtime-safe call.
- */
+ Glib::Mutex::Lock lm (reset_lock);
+ reset_pending++;
+}
+
+void
+MTC_Slave::maybe_reset ()
+{
+ reset_lock.lock ();
+
+ if (reset_pending) {
+ reset ();
+ reset_pending = 0;
+ }
+
+ reset_lock.unlock ();
+}
+void
+MTC_Slave::reset ()
+{
port->input()->reset_mtc_state ();
last_inbound_frame = 0;
@@ -458,15 +492,48 @@ MTC_Slave::reset ()
void
MTC_Slave::reset_window (nframes64_t root)
{
- window_begin = root;
+
+ /* if we're waiting for the master to catch us after seeking ahead, keep the window
+ of acceptable MTC frames wide open. otherwise, shrink it down to just 2 video frames
+ ahead of the window root (taking direction into account).
+ */
- if (session.slave_state() == Session::Running) {
- window_end = root + (session.frames_per_timecode_frame() * 2);
- } else {
- window_end = root + seekahead_distance ();
- }
+ switch (port->input()->mtc_running()) {
+ case MTC_Forward:
+ window_begin = root;
+ if (session.slave_state() == Session::Running) {
+ window_end = root + (session.frames_per_timecode_frame() * frame_tolerance);
+ } else {
+ window_end = root + seekahead_distance ();
+ }
+ DEBUG_TRACE (DEBUG::MTC, string_compose ("legal MTC window now %1 .. %2\n", window_begin, window_end));
+ break;
- DEBUG_TRACE (DEBUG::MTC, string_compose ("legal MTC window now %1 .. %2\n", window_begin, window_end));
+ case MTC_Backward:
+ if (session.slave_state() == Session::Running) {
+ nframes_t d = session.frames_per_timecode_frame() * frame_tolerance;
+ if (root > d) {
+ window_begin = root - d;
+ window_end = root;
+ } else {
+ window_begin = 0;
+ }
+ } else {
+ nframes_t d = seekahead_distance ();
+ if (root > d) {
+ window_begin = root - d;
+ } else {
+ window_begin = 0;
+ }
+ }
+ window_end = root;
+ DEBUG_TRACE (DEBUG::MTC, string_compose ("legal MTC window now %1 .. %2\n", window_begin, window_end));
+ break;
+
+ default:
+ /* do nothing */
+ break;
+ }
}
nframes64_t