consolidate all transport masters on a SafeTime object that is a member of the TransportMaster base class.
This seems to have broken some aspects of chasing/locking
This commit is contained in:
parent
147d456dbd
commit
c4fcd0c268
@ -66,6 +66,80 @@ namespace Properties {
|
|||||||
LIBARDOUR_API extern PBD::PropertyDescriptor<ARDOUR::TransportRequestType> allowed_transport_requests;
|
LIBARDOUR_API extern PBD::PropertyDescriptor<ARDOUR::TransportRequestType> allowed_transport_requests;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct LIBARDOUR_API SafeTime {
|
||||||
|
|
||||||
|
/* This object uses memory fences to provide psuedo-atomic updating of
|
||||||
|
* non-atomic data. If after reading guard1 and guard2 with correct
|
||||||
|
* memory fencing they have the same value, then we know that the other
|
||||||
|
* members are all internally consistent.
|
||||||
|
*
|
||||||
|
* Traditionally, one might do this with a mutex, but this object
|
||||||
|
* provides lock-free write update. The reader might block while
|
||||||
|
* waiting for consistency, but this is extraordinarily unlikely. In
|
||||||
|
* this sense, the design is similar to a spinlock.
|
||||||
|
*
|
||||||
|
* any update starts by incrementing guard1, with a memory fence to
|
||||||
|
* ensure no reordering of this w.r.t later operations.
|
||||||
|
*
|
||||||
|
* then we update the "non-atomic" data members.
|
||||||
|
*
|
||||||
|
* then we update guard2, with another memory fence to prevent
|
||||||
|
* reordering.
|
||||||
|
*
|
||||||
|
* ergo, if guard1 == guard2, the update of the non-atomic members is
|
||||||
|
* complete and the values stored there are consistent.
|
||||||
|
*/
|
||||||
|
|
||||||
|
boost::atomic<int> guard1;
|
||||||
|
samplepos_t position;
|
||||||
|
samplepos_t timestamp;
|
||||||
|
double speed;
|
||||||
|
boost::atomic<int> guard2;
|
||||||
|
|
||||||
|
SafeTime() {
|
||||||
|
guard1.store (0);
|
||||||
|
position = 0;
|
||||||
|
timestamp = 0;
|
||||||
|
speed = 0;
|
||||||
|
guard2.store (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset () {
|
||||||
|
guard1.store (0);
|
||||||
|
position = 0;
|
||||||
|
timestamp = 0;
|
||||||
|
speed = 0;
|
||||||
|
guard2.store (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void update (samplepos_t p, samplepos_t t, double s) {
|
||||||
|
guard1.fetch_add (1, boost::memory_order_acquire);
|
||||||
|
position = p;
|
||||||
|
timestamp = t;
|
||||||
|
speed = s;
|
||||||
|
guard2.fetch_add (1, boost::memory_order_acquire);
|
||||||
|
}
|
||||||
|
|
||||||
|
void safe_read (SafeTime& dst) const {
|
||||||
|
int tries = 0;
|
||||||
|
|
||||||
|
do {
|
||||||
|
if (tries == 10) {
|
||||||
|
std::cerr << X_("SafeTime: atomic read of current time failed, sleeping!") << std::endl;
|
||||||
|
Glib::usleep (20);
|
||||||
|
tries = 0;
|
||||||
|
}
|
||||||
|
dst.guard1.store (guard1.load (boost::memory_order_seq_cst), boost::memory_order_seq_cst);
|
||||||
|
dst.position = position;
|
||||||
|
dst.timestamp = timestamp;
|
||||||
|
dst.speed = speed;
|
||||||
|
dst.guard2.store (guard2.load (boost::memory_order_seq_cst), boost::memory_order_seq_cst);
|
||||||
|
tries++;
|
||||||
|
|
||||||
|
} while (dst.guard1.load (boost::memory_order_seq_cst) != dst.guard2.load (boost::memory_order_seq_cst));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @class TransportMaster
|
* @class TransportMaster
|
||||||
*
|
*
|
||||||
@ -138,7 +212,7 @@ class LIBARDOUR_API TransportMaster : public PBD::Stateful {
|
|||||||
* @param position - The transport position requested
|
* @param position - The transport position requested
|
||||||
* @return - The return value is currently ignored (see Session::follow_slave)
|
* @return - The return value is currently ignored (see Session::follow_slave)
|
||||||
*/
|
*/
|
||||||
virtual bool speed_and_position (double& speed, samplepos_t& position, samplepos_t now) = 0;
|
virtual bool speed_and_position (double& speed, samplepos_t& position, samplepos_t & lp, samplepos_t & when, samplepos_t now);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* reports to ARDOUR whether the TransportMaster is currently synced to its external
|
* reports to ARDOUR whether the TransportMaster is currently synced to its external
|
||||||
@ -252,6 +326,9 @@ class LIBARDOUR_API TransportMaster : public PBD::Stateful {
|
|||||||
|
|
||||||
TransportRequestType request_mask() const { return _request_mask; }
|
TransportRequestType request_mask() const { return _request_mask; }
|
||||||
void set_request_mask (TransportRequestType);
|
void set_request_mask (TransportRequestType);
|
||||||
|
|
||||||
|
void get_current (double&, samplepos_t&, samplepos_t);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
SyncSource _type;
|
SyncSource _type;
|
||||||
PBD::Property<std::string> _name;
|
PBD::Property<std::string> _name;
|
||||||
@ -264,6 +341,8 @@ class LIBARDOUR_API TransportMaster : public PBD::Stateful {
|
|||||||
PBD::Property<bool> _collect;
|
PBD::Property<bool> _collect;
|
||||||
PBD::Property<bool> _connected;
|
PBD::Property<bool> _connected;
|
||||||
|
|
||||||
|
SafeTime current;
|
||||||
|
|
||||||
/* DLL - chase incoming data */
|
/* DLL - chase incoming data */
|
||||||
|
|
||||||
int transport_direction;
|
int transport_direction;
|
||||||
@ -284,57 +363,6 @@ class LIBARDOUR_API TransportMaster : public PBD::Stateful {
|
|||||||
virtual void register_properties ();
|
virtual void register_properties ();
|
||||||
};
|
};
|
||||||
|
|
||||||
struct LIBARDOUR_API SafeTime {
|
|
||||||
boost::atomic<int> guard1;
|
|
||||||
samplepos_t position;
|
|
||||||
samplepos_t timestamp;
|
|
||||||
double speed;
|
|
||||||
boost::atomic<int> guard2;
|
|
||||||
|
|
||||||
SafeTime() {
|
|
||||||
guard1.store (0);
|
|
||||||
position = 0;
|
|
||||||
timestamp = 0;
|
|
||||||
speed = 0;
|
|
||||||
guard2.store (0);
|
|
||||||
}
|
|
||||||
|
|
||||||
SafeTime (SafeTime const & other)
|
|
||||||
: guard1 (other.guard1.load (boost::memory_order_acquire))
|
|
||||||
, position (other.position)
|
|
||||||
, timestamp (other.timestamp)
|
|
||||||
, speed (other.speed)
|
|
||||||
, guard2 (other.guard2.load (boost::memory_order_acquire))
|
|
||||||
{}
|
|
||||||
|
|
||||||
void update (samplepos_t p, samplepos_t t, double s) {
|
|
||||||
guard1.fetch_add (1, boost::memory_order_acquire);
|
|
||||||
position = p;
|
|
||||||
timestamp = t;
|
|
||||||
speed = s;
|
|
||||||
guard2.fetch_add (1, boost::memory_order_acquire);
|
|
||||||
}
|
|
||||||
|
|
||||||
void safe_read (SafeTime& dst) const {
|
|
||||||
int tries = 0;
|
|
||||||
|
|
||||||
do {
|
|
||||||
if (tries == 10) {
|
|
||||||
std::cerr << X_("SafeTime: atomic read of current time failed, sleeping!") << std::endl;
|
|
||||||
Glib::usleep (20);
|
|
||||||
tries = 0;
|
|
||||||
}
|
|
||||||
dst.guard1.store (guard1.load (boost::memory_order_seq_cst), boost::memory_order_seq_cst);
|
|
||||||
dst.position = position;
|
|
||||||
dst.timestamp = timestamp;
|
|
||||||
dst.speed = speed;
|
|
||||||
dst.guard2.store (guard2.load (boost::memory_order_seq_cst), boost::memory_order_seq_cst);
|
|
||||||
tries++;
|
|
||||||
|
|
||||||
} while (dst.guard1.load (boost::memory_order_seq_cst) != dst.guard2.load (boost::memory_order_seq_cst));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/** a helper class for any TransportMaster that receives its input via a MIDI
|
/** a helper class for any TransportMaster that receives its input via a MIDI
|
||||||
* port
|
* port
|
||||||
*/
|
*/
|
||||||
@ -377,8 +405,6 @@ class LIBARDOUR_API MTC_TransportMaster : public TimecodeTransportMaster, public
|
|||||||
|
|
||||||
void pre_process (pframes_t nframes, samplepos_t now, boost::optional<samplepos_t>);
|
void pre_process (pframes_t nframes, samplepos_t now, boost::optional<samplepos_t>);
|
||||||
|
|
||||||
bool speed_and_position (double&, samplepos_t&, samplepos_t);
|
|
||||||
|
|
||||||
bool locked() const;
|
bool locked() const;
|
||||||
bool ok() const;
|
bool ok() const;
|
||||||
void handle_locate (const MIDI::byte*);
|
void handle_locate (const MIDI::byte*);
|
||||||
@ -399,7 +425,6 @@ class LIBARDOUR_API MTC_TransportMaster : public TimecodeTransportMaster, public
|
|||||||
|
|
||||||
static const int sample_tolerance;
|
static const int sample_tolerance;
|
||||||
|
|
||||||
SafeTime current;
|
|
||||||
samplepos_t mtc_frame; /* current time */
|
samplepos_t mtc_frame; /* current time */
|
||||||
double mtc_frame_dll;
|
double mtc_frame_dll;
|
||||||
samplepos_t last_inbound_frame; /* when we got it; audio clocked */
|
samplepos_t last_inbound_frame; /* when we got it; audio clocked */
|
||||||
@ -430,7 +455,6 @@ class LIBARDOUR_API MTC_TransportMaster : public TimecodeTransportMaster, public
|
|||||||
void update_mtc_qtr (MIDI::Parser&, int, samplepos_t);
|
void update_mtc_qtr (MIDI::Parser&, int, samplepos_t);
|
||||||
void update_mtc_time (const MIDI::byte *, bool, samplepos_t);
|
void update_mtc_time (const MIDI::byte *, bool, samplepos_t);
|
||||||
void update_mtc_status (MIDI::MTC_Status);
|
void update_mtc_status (MIDI::MTC_Status);
|
||||||
void read_current (SafeTime *) const;
|
|
||||||
void reset_window (samplepos_t);
|
void reset_window (samplepos_t);
|
||||||
bool outside_window (samplepos_t) const;
|
bool outside_window (samplepos_t) const;
|
||||||
void init_mtc_dll(samplepos_t, double);
|
void init_mtc_dll(samplepos_t, double);
|
||||||
@ -446,7 +470,6 @@ public:
|
|||||||
void set_session (Session*);
|
void set_session (Session*);
|
||||||
|
|
||||||
void pre_process (pframes_t nframes, samplepos_t now, boost::optional<samplepos_t>);
|
void pre_process (pframes_t nframes, samplepos_t now, boost::optional<samplepos_t>);
|
||||||
bool speed_and_position (double&, samplepos_t&, samplepos_t);
|
|
||||||
|
|
||||||
bool locked() const;
|
bool locked() const;
|
||||||
bool ok() const;
|
bool ok() const;
|
||||||
@ -482,10 +505,7 @@ public:
|
|||||||
LTCFrameExt prev_sample;
|
LTCFrameExt prev_sample;
|
||||||
bool fps_detected;
|
bool fps_detected;
|
||||||
|
|
||||||
samplecnt_t monotonic_cnt;
|
samplecnt_t monotonic_cnt;
|
||||||
samplecnt_t last_timestamp;
|
|
||||||
samplecnt_t last_ltc_sample;
|
|
||||||
double ltc_speed;
|
|
||||||
int delayedlocked;
|
int delayedlocked;
|
||||||
|
|
||||||
int ltc_detect_fps_cnt;
|
int ltc_detect_fps_cnt;
|
||||||
@ -513,7 +533,6 @@ class LIBARDOUR_API MIDIClock_TransportMaster : public TransportMaster, public T
|
|||||||
void pre_process (pframes_t nframes, samplepos_t now, boost::optional<samplepos_t>);
|
void pre_process (pframes_t nframes, samplepos_t now, boost::optional<samplepos_t>);
|
||||||
|
|
||||||
void rebind (MidiPort&);
|
void rebind (MidiPort&);
|
||||||
bool speed_and_position (double&, samplepos_t&, samplepos_t);
|
|
||||||
|
|
||||||
bool locked() const;
|
bool locked() const;
|
||||||
bool ok() const;
|
bool ok() const;
|
||||||
@ -558,13 +577,12 @@ class LIBARDOUR_API MIDIClock_TransportMaster : public TransportMaster, public T
|
|||||||
void start (MIDI::Parser& parser, samplepos_t timestamp);
|
void start (MIDI::Parser& parser, samplepos_t timestamp);
|
||||||
void contineu (MIDI::Parser& parser, samplepos_t timestamp);
|
void contineu (MIDI::Parser& parser, samplepos_t timestamp);
|
||||||
void stop (MIDI::Parser& parser, samplepos_t timestamp);
|
void stop (MIDI::Parser& parser, samplepos_t timestamp);
|
||||||
void position (MIDI::Parser& parser, MIDI::byte* message, size_t size);
|
void position (MIDI::Parser& parser, MIDI::byte* message, size_t size, samplepos_t timestamp);
|
||||||
// we can't use continue because it is a C++ keyword
|
// we can't use continue because it is a C++ keyword
|
||||||
void calculate_one_ppqn_in_samples_at(samplepos_t time);
|
void calculate_one_ppqn_in_samples_at(samplepos_t time);
|
||||||
samplepos_t calculate_song_position(uint16_t song_position_in_sixteenth_notes);
|
samplepos_t calculate_song_position(uint16_t song_position_in_sixteenth_notes);
|
||||||
void calculate_filter_coefficients (double qpm);
|
void calculate_filter_coefficients (double qpm);
|
||||||
void update_midi_clock (MIDI::Parser& parser, samplepos_t timestamp);
|
void update_midi_clock (MIDI::Parser& parser, samplepos_t timestamp);
|
||||||
void read_current (SafeTime *) const;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class LIBARDOUR_API Engine_TransportMaster : public TransportMaster
|
class LIBARDOUR_API Engine_TransportMaster : public TransportMaster
|
||||||
@ -574,7 +592,7 @@ class LIBARDOUR_API Engine_TransportMaster : public TransportMaster
|
|||||||
~Engine_TransportMaster ();
|
~Engine_TransportMaster ();
|
||||||
|
|
||||||
void pre_process (pframes_t nframes, samplepos_t now, boost::optional<samplepos_t>);
|
void pre_process (pframes_t nframes, samplepos_t now, boost::optional<samplepos_t>);
|
||||||
bool speed_and_position (double& speed, samplepos_t& pos, samplepos_t);
|
bool speed_and_position (double& speed, samplepos_t& pos, samplepos_t &, samplepos_t &, samplepos_t);
|
||||||
|
|
||||||
bool starting() const { return _starting; }
|
bool starting() const { return _starting; }
|
||||||
bool locked() const;
|
bool locked() const;
|
||||||
|
@ -76,7 +76,7 @@ Engine_TransportMaster::pre_process (pframes_t, samplepos_t, boost::optional<sam
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
Engine_TransportMaster::speed_and_position (double& sp, samplepos_t& position, samplepos_t /* now */)
|
Engine_TransportMaster::speed_and_position (double& sp, samplepos_t& position, samplepos_t& lp, samplepos_t & when, samplepos_t now)
|
||||||
{
|
{
|
||||||
boost::shared_ptr<AudioBackend> backend = engine.current_backend();
|
boost::shared_ptr<AudioBackend> backend = engine.current_backend();
|
||||||
|
|
||||||
@ -88,6 +88,9 @@ Engine_TransportMaster::speed_and_position (double& sp, samplepos_t& position, s
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lp = now;
|
||||||
|
when = now;
|
||||||
|
|
||||||
_current_delta = 0;
|
_current_delta = 0;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -53,8 +53,6 @@ LTC_TransportMaster::LTC_TransportMaster (std::string const & name)
|
|||||||
, samples_per_ltc_frame (0)
|
, samples_per_ltc_frame (0)
|
||||||
, fps_detected (false)
|
, fps_detected (false)
|
||||||
, monotonic_cnt (0)
|
, monotonic_cnt (0)
|
||||||
, last_timestamp (0)
|
|
||||||
, last_ltc_sample (0)
|
|
||||||
, delayedlocked (10)
|
, delayedlocked (10)
|
||||||
, ltc_detect_fps_cnt (0)
|
, ltc_detect_fps_cnt (0)
|
||||||
, ltc_detect_fps_max (0)
|
, ltc_detect_fps_max (0)
|
||||||
@ -185,11 +183,10 @@ LTC_TransportMaster::reset (bool with_ts)
|
|||||||
{
|
{
|
||||||
DEBUG_TRACE (DEBUG::LTC, "LTC reset()\n");
|
DEBUG_TRACE (DEBUG::LTC, "LTC reset()\n");
|
||||||
if (with_ts) {
|
if (with_ts) {
|
||||||
last_timestamp = 0;
|
current.update (current.position, 0, current.speed);
|
||||||
_current_delta = 0;
|
_current_delta = 0;
|
||||||
}
|
}
|
||||||
transport_direction = 0;
|
transport_direction = 0;
|
||||||
ltc_speed = 0;
|
|
||||||
sync_lock_broken = false;
|
sync_lock_broken = false;
|
||||||
monotonic_cnt = 0;
|
monotonic_cnt = 0;
|
||||||
}
|
}
|
||||||
@ -460,55 +457,32 @@ LTC_TransportMaster::process_ltc(samplepos_t const now)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
samplepos_t cur_timestamp = sample.off_end + 1;
|
samplepos_t cur_timestamp = sample.off_end + 1;
|
||||||
|
double ltc_speed = current.speed;
|
||||||
|
|
||||||
DEBUG_TRACE (DEBUG::LTC, string_compose ("LTC S: %1 LS: %2 N: %3 L: %4\n", ltc_sample, last_ltc_sample, cur_timestamp, last_timestamp));
|
DEBUG_TRACE (DEBUG::LTC, string_compose ("LTC S: %1 LS: %2 N: %3 L: %4\n", ltc_sample, current.position, cur_timestamp, current.timestamp));
|
||||||
|
|
||||||
if (cur_timestamp <= last_timestamp || last_timestamp == 0) {
|
if (cur_timestamp <= current.timestamp || current.timestamp == 0) {
|
||||||
DEBUG_TRACE (DEBUG::LTC, string_compose ("LTC speed: UNCHANGED: %1\n", ltc_speed));
|
DEBUG_TRACE (DEBUG::LTC, string_compose ("LTC speed: UNCHANGED: %1\n", current.speed));
|
||||||
} else {
|
} else {
|
||||||
ltc_speed = double (ltc_sample - last_ltc_sample) / double (cur_timestamp - last_timestamp);
|
ltc_speed = double (ltc_sample - current.position) / double (cur_timestamp - current.timestamp);
|
||||||
|
|
||||||
|
/* provide a .1% deadzone to lock the speed */
|
||||||
|
if (fabs (ltc_speed - 1.0) <= 0.001) {
|
||||||
|
ltc_speed = 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fabs (ltc_speed) > 10.0) {
|
||||||
|
ltc_speed = 0;
|
||||||
|
}
|
||||||
|
|
||||||
DEBUG_TRACE (DEBUG::LTC, string_compose ("LTC speed: %1\n", ltc_speed));
|
DEBUG_TRACE (DEBUG::LTC, string_compose ("LTC speed: %1\n", ltc_speed));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fabs (ltc_speed) > 10.0) {
|
current.update (ltc_sample, cur_timestamp, ltc_speed);
|
||||||
ltc_speed = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
last_timestamp = cur_timestamp;
|
|
||||||
last_ltc_sample = ltc_sample;
|
|
||||||
|
|
||||||
} /* end foreach decoded LTC sample */
|
} /* end foreach decoded LTC sample */
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
|
||||||
LTC_TransportMaster::speed_and_position (double& speed, samplepos_t& pos, samplepos_t now)
|
|
||||||
{
|
|
||||||
if (!_collect || last_timestamp == 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* XXX these are not atomics and maybe modified in a thread other other than the one
|
|
||||||
that is executing this.
|
|
||||||
*/
|
|
||||||
|
|
||||||
speed = ltc_speed;
|
|
||||||
|
|
||||||
/* provide a .1% deadzone to lock the speed */
|
|
||||||
if (fabs (speed - 1.0) <= 0.001) {
|
|
||||||
speed = 1.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (speed != 0 && delayedlocked == 0 && fabs(speed) != 1.0) {
|
|
||||||
sync_lock_broken = true;
|
|
||||||
DEBUG_TRACE (DEBUG::LTC, string_compose ("LTC speed not locked %1 based on %2\n", speed, ltc_speed));
|
|
||||||
}
|
|
||||||
|
|
||||||
pos = last_ltc_sample;
|
|
||||||
pos += (now - last_timestamp) * speed;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
LTC_TransportMaster::pre_process (ARDOUR::pframes_t nframes, samplepos_t now, boost::optional<samplepos_t> session_pos)
|
LTC_TransportMaster::pre_process (ARDOUR::pframes_t nframes, samplepos_t now, boost::optional<samplepos_t> session_pos)
|
||||||
{
|
{
|
||||||
@ -517,14 +491,14 @@ LTC_TransportMaster::pre_process (ARDOUR::pframes_t nframes, samplepos_t now, bo
|
|||||||
monotonic_cnt = now;
|
monotonic_cnt = now;
|
||||||
|
|
||||||
DEBUG_TRACE (DEBUG::LTC, string_compose ("pre-process - TID:%1 | latency: %2 | skip %3 | session ? %4| last %5 | dir %6 | sp %7\n",
|
DEBUG_TRACE (DEBUG::LTC, string_compose ("pre-process - TID:%1 | latency: %2 | skip %3 | session ? %4| last %5 | dir %6 | sp %7\n",
|
||||||
pthread_name(), ltc_slave_latency.max, skip, (_session ? 'y' : 'n'), last_timestamp, transport_direction, ltc_speed));
|
pthread_name(), ltc_slave_latency.max, skip, (_session ? 'y' : 'n'), current.timestamp, transport_direction, current.speed));
|
||||||
|
|
||||||
if (last_timestamp == 0) {
|
if (current.timestamp == 0) {
|
||||||
if (delayedlocked < 10) {
|
if (delayedlocked < 10) {
|
||||||
++delayedlocked;
|
++delayedlocked;
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (ltc_speed != 0) {
|
} else if (current.speed != 0) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -555,11 +529,11 @@ LTC_TransportMaster::pre_process (ARDOUR::pframes_t nframes, samplepos_t now, bo
|
|||||||
|
|
||||||
process_ltc (now);
|
process_ltc (now);
|
||||||
|
|
||||||
if (last_timestamp == 0) {
|
if (current.timestamp == 0) {
|
||||||
DEBUG_TRACE (DEBUG::LTC, "last timestamp == 0\n");
|
DEBUG_TRACE (DEBUG::LTC, "last timestamp == 0\n");
|
||||||
return;
|
return;
|
||||||
} else if (ltc_speed != 0) {
|
} else if (current.speed != 0) {
|
||||||
DEBUG_TRACE (DEBUG::LTC, string_compose ("speed non-zero (%1)\n", ltc_speed));
|
DEBUG_TRACE (DEBUG::LTC, string_compose ("speed non-zero (%1)\n", current.speed));
|
||||||
if (delayedlocked > 1) {
|
if (delayedlocked > 1) {
|
||||||
delayedlocked--;
|
delayedlocked--;
|
||||||
} else if (_current_delta == 0) {
|
} else if (_current_delta == 0) {
|
||||||
@ -567,7 +541,7 @@ LTC_TransportMaster::pre_process (ARDOUR::pframes_t nframes, samplepos_t now, bo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (abs (now - last_timestamp) > FLYWHEEL_TIMEOUT) {
|
if (abs (now - current.timestamp) > FLYWHEEL_TIMEOUT) {
|
||||||
DEBUG_TRACE (DEBUG::LTC, "flywheel timeout\n");
|
DEBUG_TRACE (DEBUG::LTC, "flywheel timeout\n");
|
||||||
reset();
|
reset();
|
||||||
/* don't change position from last known */
|
/* don't change position from last known */
|
||||||
@ -575,8 +549,13 @@ LTC_TransportMaster::pre_process (ARDOUR::pframes_t nframes, samplepos_t now, bo
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!sync_lock_broken && current.speed != 0 && delayedlocked == 0 && fabs(current.speed) != 1.0) {
|
||||||
|
sync_lock_broken = true;
|
||||||
|
DEBUG_TRACE (DEBUG::LTC, string_compose ("LTC speed not locked based on %1\n", current.speed));
|
||||||
|
}
|
||||||
|
|
||||||
if (session_pos) {
|
if (session_pos) {
|
||||||
const samplepos_t current_pos = last_ltc_sample + ((now - last_timestamp) * ltc_speed);
|
const samplepos_t current_pos = current.position + ((now - current.timestamp) * current.speed);
|
||||||
_current_delta = current_pos - *session_pos;
|
_current_delta = current_pos - *session_pos;
|
||||||
} else {
|
} else {
|
||||||
_current_delta = 0;
|
_current_delta = 0;
|
||||||
@ -606,7 +585,7 @@ LTC_TransportMaster::apparent_timecode_format () const
|
|||||||
std::string
|
std::string
|
||||||
LTC_TransportMaster::position_string() const
|
LTC_TransportMaster::position_string() const
|
||||||
{
|
{
|
||||||
if (!_collect || last_timestamp == 0) {
|
if (!_collect || current.timestamp == 0) {
|
||||||
return " --:--:--:--";
|
return " --:--:--:--";
|
||||||
}
|
}
|
||||||
return Timecode::timecode_format_time(timecode);
|
return Timecode::timecode_format_time(timecode);
|
||||||
@ -617,9 +596,9 @@ LTC_TransportMaster::delta_string() const
|
|||||||
{
|
{
|
||||||
char delta[80];
|
char delta[80];
|
||||||
|
|
||||||
if (!_collect || last_timestamp == 0) {
|
if (!_collect || current.timestamp == 0) {
|
||||||
snprintf (delta, sizeof(delta), "\u2012\u2012\u2012\u2012");
|
snprintf (delta, sizeof(delta), "\u2012\u2012\u2012\u2012");
|
||||||
} else if ((monotonic_cnt - last_timestamp) > 2 * samples_per_ltc_frame) {
|
} else if ((monotonic_cnt - current.timestamp) > 2 * samples_per_ltc_frame) {
|
||||||
snprintf (delta, sizeof(delta), "%s", _("flywheel"));
|
snprintf (delta, sizeof(delta), "%s", _("flywheel"));
|
||||||
} else {
|
} else {
|
||||||
snprintf (delta, sizeof(delta), "\u0394<span foreground=\"%s\" face=\"monospace\" >%s%s%lld</span>sm",
|
snprintf (delta, sizeof(delta), "\u0394<span foreground=\"%s\" face=\"monospace\" >%s%s%lld</span>sm",
|
||||||
|
@ -49,10 +49,7 @@ using namespace PBD;
|
|||||||
MIDIClock_TransportMaster::MIDIClock_TransportMaster (std::string const & name, int ppqn)
|
MIDIClock_TransportMaster::MIDIClock_TransportMaster (std::string const & name, int ppqn)
|
||||||
: TransportMaster (MIDIClock, name)
|
: TransportMaster (MIDIClock, name)
|
||||||
, ppqn (ppqn)
|
, ppqn (ppqn)
|
||||||
, last_timestamp (0)
|
|
||||||
, should_be_position (0)
|
|
||||||
, midi_clock_count (0)
|
, midi_clock_count (0)
|
||||||
, _speed (0)
|
|
||||||
, _running (false)
|
, _running (false)
|
||||||
, _bpm (0)
|
, _bpm (0)
|
||||||
{
|
{
|
||||||
@ -70,7 +67,7 @@ void
|
|||||||
MIDIClock_TransportMaster::init ()
|
MIDIClock_TransportMaster::init ()
|
||||||
{
|
{
|
||||||
midi_clock_count = 0;
|
midi_clock_count = 0;
|
||||||
last_timestamp = 0;
|
current.reset ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -88,46 +85,26 @@ MIDIClock_TransportMaster::set_session (Session *session)
|
|||||||
parser.start.connect_same_thread (port_connections, boost::bind (&MIDIClock_TransportMaster::start, this, _1, _2));
|
parser.start.connect_same_thread (port_connections, boost::bind (&MIDIClock_TransportMaster::start, this, _1, _2));
|
||||||
parser.contineu.connect_same_thread (port_connections, boost::bind (&MIDIClock_TransportMaster::contineu, this, _1, _2));
|
parser.contineu.connect_same_thread (port_connections, boost::bind (&MIDIClock_TransportMaster::contineu, this, _1, _2));
|
||||||
parser.stop.connect_same_thread (port_connections, boost::bind (&MIDIClock_TransportMaster::stop, this, _1, _2));
|
parser.stop.connect_same_thread (port_connections, boost::bind (&MIDIClock_TransportMaster::stop, this, _1, _2));
|
||||||
parser.position.connect_same_thread (port_connections, boost::bind (&MIDIClock_TransportMaster::position, this, _1, _2, 3));
|
parser.position.connect_same_thread (port_connections, boost::bind (&MIDIClock_TransportMaster::position, this, _1, _2, _3, _4));
|
||||||
|
|
||||||
reset ();
|
reset ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
|
||||||
MIDIClock_TransportMaster::speed_and_position (double& speed, samplepos_t& pos, samplepos_t now)
|
|
||||||
{
|
|
||||||
if (!_running || !_collect) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fabs (_speed - 1.0) < 0.001) {
|
|
||||||
speed = 1.0;
|
|
||||||
} else {
|
|
||||||
speed = _speed;
|
|
||||||
}
|
|
||||||
|
|
||||||
pos = should_be_position;
|
|
||||||
pos += (now - last_timestamp) * _speed;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
MIDIClock_TransportMaster::pre_process (MIDI::pframes_t nframes, samplepos_t now, boost::optional<samplepos_t> session_pos)
|
MIDIClock_TransportMaster::pre_process (MIDI::pframes_t nframes, samplepos_t now, boost::optional<samplepos_t> session_pos)
|
||||||
{
|
{
|
||||||
/* Read and parse incoming MIDI */
|
/* Read and parse incoming MIDI */
|
||||||
|
|
||||||
DEBUG_TRACE (DEBUG::MidiClock, string_compose ("preprocess with lt = %1 @ %2, running ? %3\n", last_timestamp, now, _running));
|
DEBUG_TRACE (DEBUG::MidiClock, string_compose ("preprocess with lt = %1 @ %2, running ? %3\n", current.timestamp, now, _running));
|
||||||
|
|
||||||
_midi_port->read_and_parse_entire_midi_buffer_with_no_speed_adjustment (nframes, parser, now);
|
_midi_port->read_and_parse_entire_midi_buffer_with_no_speed_adjustment (nframes, parser, now);
|
||||||
|
|
||||||
/* no clock messages ever, or no clock messages for 1/4 second ? conclude that its stopped */
|
/* no clock messages ever, or no clock messages for 1/4 second ? conclude that its stopped */
|
||||||
|
|
||||||
if (!last_timestamp || (now > last_timestamp && ((now - last_timestamp) > (ENGINE->sample_rate() / 4)))) {
|
if (!last_timestamp || (now > last_timestamp && ((now - last_timestamp) > (ENGINE->sample_rate() / 4)))) {
|
||||||
_speed = 0.0;
|
current.update (current.position, 0, 0);
|
||||||
_bpm = 0.0;
|
_bpm = 0.0;
|
||||||
last_timestamp = 0;
|
|
||||||
_running = false;
|
_running = false;
|
||||||
_current_delta = 0;
|
_current_delta = 0;
|
||||||
midi_clock_count = 0;
|
midi_clock_count = 0;
|
||||||
@ -137,18 +114,18 @@ MIDIClock_TransportMaster::pre_process (MIDI::pframes_t nframes, samplepos_t now
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!_running && midi_clock_count == 0 && session_pos) {
|
if (!_running && midi_clock_count == 0 && session_pos) {
|
||||||
should_be_position = *session_pos;
|
current.update (*session_pos, now, current.speed);
|
||||||
DEBUG_TRACE (DEBUG::MidiClock, string_compose ("set sbp to %1\n", should_be_position));
|
DEBUG_TRACE (DEBUG::MidiClock, string_compose ("set sbp to %1\n", current.position));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (session_pos) {
|
if (session_pos) {
|
||||||
const samplepos_t current_pos = should_be_position + ((now - last_timestamp) * _speed);
|
const samplepos_t current_pos = current.position + ((now - current.timestamp) * current.speed);
|
||||||
_current_delta = current_pos - *session_pos;
|
_current_delta = current_pos - *session_pos;
|
||||||
} else {
|
} else {
|
||||||
_current_delta = 0;
|
_current_delta = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
DEBUG_TRACE (DEBUG::MidiClock, string_compose ("speed_and_position: speed %1 should-be %2 transport %3 \n", _speed, should_be_position, _session->transport_sample()));
|
DEBUG_TRACE (DEBUG::MidiClock, string_compose ("speed_and_position: speed %1 should-be %2 transport %3 \n", current.speed, current.position, _session->transport_sample()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -197,21 +174,21 @@ MIDIClock_TransportMaster::update_midi_clock (Parser& /*parser*/, samplepos_t ti
|
|||||||
samplepos_t elapsed_since_start = timestamp - first_timestamp;
|
samplepos_t elapsed_since_start = timestamp - first_timestamp;
|
||||||
double e = 0;
|
double e = 0;
|
||||||
|
|
||||||
calculate_one_ppqn_in_samples_at (should_be_position);
|
calculate_one_ppqn_in_samples_at (current.position);
|
||||||
|
|
||||||
DEBUG_TRACE (DEBUG::MidiClock, string_compose ("clock count %1, sbp %2\n", midi_clock_count, should_be_position));
|
DEBUG_TRACE (DEBUG::MidiClock, string_compose ("clock count %1, sbp %2\n", midi_clock_count, current.position));
|
||||||
|
|
||||||
if (midi_clock_count == 0) {
|
if (midi_clock_count == 0) {
|
||||||
/* second 0xf8 message after start/reset has arrived */
|
/* second 0xf8 message after start/reset has arrived */
|
||||||
|
|
||||||
first_timestamp = timestamp;
|
first_timestamp = timestamp;
|
||||||
last_timestamp = timestamp;
|
current.update (0, timestamp, 0);
|
||||||
|
|
||||||
DEBUG_TRACE (DEBUG::MidiClock, string_compose ("first clock message after start received @ %1\n", timestamp));
|
DEBUG_TRACE (DEBUG::MidiClock, string_compose ("first clock message after start received @ %1\n", timestamp));
|
||||||
|
|
||||||
midi_clock_count++;
|
midi_clock_count++;
|
||||||
|
|
||||||
should_be_position += one_ppqn_in_samples;
|
current.position += one_ppqn_in_samples;
|
||||||
|
|
||||||
} else if (midi_clock_count == 1) {
|
} else if (midi_clock_count == 1) {
|
||||||
|
|
||||||
@ -233,7 +210,7 @@ MIDIClock_TransportMaster::update_midi_clock (Parser& /*parser*/, samplepos_t ti
|
|||||||
t1 = t0 + e2; /* timestamp we predict for the next 0xf8 clock message */
|
t1 = t0 + e2; /* timestamp we predict for the next 0xf8 clock message */
|
||||||
|
|
||||||
midi_clock_count++;
|
midi_clock_count++;
|
||||||
should_be_position += one_ppqn_in_samples;
|
current.update (one_ppqn_in_samples, timestamp, 0);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
@ -254,7 +231,7 @@ MIDIClock_TransportMaster::update_midi_clock (Parser& /*parser*/, samplepos_t ti
|
|||||||
|
|
||||||
/* _speed is relative to session tempo map */
|
/* _speed is relative to session tempo map */
|
||||||
|
|
||||||
_speed = predicted_clock_interval_in_samples / one_ppqn_in_samples;
|
double speed = predicted_clock_interval_in_samples / one_ppqn_in_samples;
|
||||||
|
|
||||||
/* _bpm (really, _qpm) is absolute */
|
/* _bpm (really, _qpm) is absolute */
|
||||||
|
|
||||||
@ -278,14 +255,14 @@ MIDIClock_TransportMaster::update_midi_clock (Parser& /*parser*/, samplepos_t ti
|
|||||||
}
|
}
|
||||||
|
|
||||||
midi_clock_count++;
|
midi_clock_count++;
|
||||||
should_be_position += one_ppqn_in_samples;
|
current.update (current.position + one_ppqn_in_samples, timestamp, speed);
|
||||||
}
|
}
|
||||||
|
|
||||||
DEBUG_TRACE (DEBUG::MidiClock, string_compose ("clock #%1 @ %2 should-be %3 transport %4 error %5 appspeed %6 "
|
DEBUG_TRACE (DEBUG::MidiClock, string_compose ("clock #%1 @ %2 should-be %3 transport %4 error %5 appspeed %6 "
|
||||||
"read-delta %7 should-be delta %8 t1-t0 %9 t0 %10 t1 %11 framerate %12 engine %13 running %14\n",
|
"read-delta %7 should-be delta %8 t1-t0 %9 t0 %10 t1 %11 framerate %12 engine %13 running %14\n",
|
||||||
midi_clock_count, // #
|
midi_clock_count, // #
|
||||||
elapsed_since_start, // @
|
elapsed_since_start, // @
|
||||||
should_be_position, // should-be
|
current.position, // should-be
|
||||||
_session->transport_sample(), // transport
|
_session->transport_sample(), // transport
|
||||||
e, // error
|
e, // error
|
||||||
(t1 - t0) / one_ppqn_in_samples, // appspeed
|
(t1 - t0) / one_ppqn_in_samples, // appspeed
|
||||||
@ -311,7 +288,7 @@ MIDIClock_TransportMaster::start (Parser& /*parser*/, samplepos_t timestamp)
|
|||||||
if (!_running) {
|
if (!_running) {
|
||||||
reset();
|
reset();
|
||||||
_running = true;
|
_running = true;
|
||||||
should_be_position = _session->transport_sample();
|
current.update (_session->transport_sample(), timestamp, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -320,9 +297,7 @@ MIDIClock_TransportMaster::reset ()
|
|||||||
{
|
{
|
||||||
DEBUG_TRACE (DEBUG::MidiClock, string_compose ("MidiClock Master reset(): calculated filter for period size %2\n", ENGINE->samples_per_cycle()));
|
DEBUG_TRACE (DEBUG::MidiClock, string_compose ("MidiClock Master reset(): calculated filter for period size %2\n", ENGINE->samples_per_cycle()));
|
||||||
|
|
||||||
should_be_position = _session->transport_sample();
|
current.update (_session->transport_sample(), 0, 0);
|
||||||
_speed = 0;
|
|
||||||
last_timestamp = 0;
|
|
||||||
|
|
||||||
_running = false;
|
_running = false;
|
||||||
_current_delta = 0;
|
_current_delta = 0;
|
||||||
@ -337,7 +312,7 @@ MIDIClock_TransportMaster::contineu (Parser& /*parser*/, samplepos_t /*timestamp
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
MIDIClock_TransportMaster::stop (Parser& /*parser*/, samplepos_t /*timestamp*/)
|
MIDIClock_TransportMaster::stop (Parser& /*parser*/, samplepos_t timestamp)
|
||||||
{
|
{
|
||||||
DEBUG_TRACE (DEBUG::MidiClock, "MIDIClock_TransportMaster got stop message\n");
|
DEBUG_TRACE (DEBUG::MidiClock, "MIDIClock_TransportMaster got stop message\n");
|
||||||
|
|
||||||
@ -356,12 +331,12 @@ MIDIClock_TransportMaster::stop (Parser& /*parser*/, samplepos_t /*timestamp*/)
|
|||||||
//
|
//
|
||||||
// find out the last MIDI beat: go back #midi_clocks mod 6
|
// find out the last MIDI beat: go back #midi_clocks mod 6
|
||||||
// and lets hope the tempo didnt change in those last 6 beats :)
|
// and lets hope the tempo didnt change in those last 6 beats :)
|
||||||
should_be_position -= (midi_clock_count % 6) * one_ppqn_in_samples;
|
current.update (current.position - (midi_clock_count % 6) * one_ppqn_in_samples, timestamp, current.speed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
MIDIClock_TransportMaster::position (Parser& /*parser*/, MIDI::byte* message, size_t size)
|
MIDIClock_TransportMaster::position (Parser& /*parser*/, MIDI::byte* message, size_t size, samplepos_t timestamp)
|
||||||
{
|
{
|
||||||
// we are not supposed to get position messages while we are running
|
// we are not supposed to get position messages while we are running
|
||||||
// so lets be robust and ignore those
|
// so lets be robust and ignore those
|
||||||
@ -379,9 +354,7 @@ MIDIClock_TransportMaster::position (Parser& /*parser*/, MIDI::byte* message, si
|
|||||||
|
|
||||||
DEBUG_TRACE (DEBUG::MidiClock, string_compose ("Song Position: %1 samples: %2\n", position_in_sixteenth_notes, position_in_samples));
|
DEBUG_TRACE (DEBUG::MidiClock, string_compose ("Song Position: %1 samples: %2\n", position_in_sixteenth_notes, position_in_samples));
|
||||||
|
|
||||||
should_be_position = position_in_samples;
|
current.update (position_in_samples, timestamp, current.speed);
|
||||||
last_timestamp = 0;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
@ -132,6 +132,8 @@ MTC_TransportMaster::pre_process (MIDI::pframes_t nframes, samplepos_t now, boos
|
|||||||
{
|
{
|
||||||
/* Read and parse incoming MIDI */
|
/* Read and parse incoming MIDI */
|
||||||
|
|
||||||
|
maybe_reset ();
|
||||||
|
|
||||||
_midi_port->read_and_parse_entire_midi_buffer_with_no_speed_adjustment (nframes, parser, now);
|
_midi_port->read_and_parse_entire_midi_buffer_with_no_speed_adjustment (nframes, parser, now);
|
||||||
|
|
||||||
if (session_pos) {
|
if (session_pos) {
|
||||||
@ -222,18 +224,9 @@ MTC_TransportMaster::reset (bool with_position)
|
|||||||
DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC_TransportMaster reset %1\n", with_position?"with position":"without position"));
|
DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC_TransportMaster reset %1\n", with_position?"with position":"without position"));
|
||||||
|
|
||||||
if (with_position) {
|
if (with_position) {
|
||||||
last_inbound_frame = 0;
|
current.update (0, 0, 0);
|
||||||
current.guard1++;
|
|
||||||
current.position = 0;
|
|
||||||
current.timestamp = 0;
|
|
||||||
current.speed = 0;
|
|
||||||
current.guard2++;
|
|
||||||
} else {
|
} else {
|
||||||
last_inbound_frame = 0;
|
current.update (current.position, 0, 0);
|
||||||
current.guard1++;
|
|
||||||
current.timestamp = 0;
|
|
||||||
current.speed = 0;
|
|
||||||
current.guard2++;
|
|
||||||
}
|
}
|
||||||
first_mtc_timestamp = 0;
|
first_mtc_timestamp = 0;
|
||||||
window_begin = 0;
|
window_begin = 0;
|
||||||
@ -294,8 +287,6 @@ MTC_TransportMaster::update_mtc_qtr (Parser& p, int which_qtr, samplepos_t now)
|
|||||||
DEBUG_TRACE (DEBUG::MTC, string_compose ("qtr sample DLL t0:%1 t1:%2 err:%3 spd:%4 ddt:%5\n", t0, t1, e, mtc_speed, e2 - qtr_d));
|
DEBUG_TRACE (DEBUG::MTC, string_compose ("qtr sample DLL t0:%1 t1:%2 err:%3 spd:%4 ddt:%5\n", t0, t1, e, mtc_speed, e2 - qtr_d));
|
||||||
|
|
||||||
current.update (mtc_frame, now, mtc_speed);
|
current.update (mtc_frame, now, mtc_speed);
|
||||||
|
|
||||||
last_inbound_frame = now;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
maybe_reset ();
|
maybe_reset ();
|
||||||
@ -481,9 +472,6 @@ MTC_TransportMaster::update_mtc_time (const MIDI::byte *msg, bool was_full, samp
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (now) {
|
|
||||||
last_inbound_frame = now;
|
|
||||||
}
|
|
||||||
busy_guard2++;
|
busy_guard2++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -549,62 +537,6 @@ MTC_TransportMaster::reset_window (samplepos_t root)
|
|||||||
DEBUG_TRACE (DEBUG::MTC, string_compose ("reset MTC window @ %3, now %1 .. %2\n", window_begin, window_end, root));
|
DEBUG_TRACE (DEBUG::MTC, string_compose ("reset MTC window @ %3, now %1 .. %2\n", window_begin, window_end, root));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* main entry point from session_process.cc
|
|
||||||
xo * in process callback context */
|
|
||||||
bool
|
|
||||||
MTC_TransportMaster::speed_and_position (double& speed, samplepos_t& pos, samplepos_t now)
|
|
||||||
{
|
|
||||||
SafeTime last;
|
|
||||||
|
|
||||||
if (!_collect) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
current.safe_read (last);
|
|
||||||
|
|
||||||
DEBUG_TRACE (DEBUG::MTC, string_compose ("speed&pos: timestamp %1 speed %2 dir %4 now %5 last-in %6\n",
|
|
||||||
last.timestamp,
|
|
||||||
last.speed,
|
|
||||||
transport_direction,
|
|
||||||
now,
|
|
||||||
last_inbound_frame));
|
|
||||||
|
|
||||||
if (last.timestamp == 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (last_inbound_frame && now > last_inbound_frame && now - last_inbound_frame > labs(seekahead_distance())) {
|
|
||||||
/* 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;
|
|
||||||
_current_delta = 0;
|
|
||||||
queue_reset (false);
|
|
||||||
DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC not seen for 2 samples - reset pending, pos = %1\n", pos));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC::speed_and_position mtc-tme: %1 mtc-pos: %2 mtc-spd: %3\n", last.timestamp, last.position, last.speed));
|
|
||||||
|
|
||||||
speed = last.speed;
|
|
||||||
|
|
||||||
/* provide a .1% deadzone to lock the speed */
|
|
||||||
if (fabs (speed - 1.0) <= 0.001) {
|
|
||||||
speed = 1.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
pos = last.position;
|
|
||||||
pos += (now - last.timestamp) * speed;
|
|
||||||
|
|
||||||
DEBUG_TRACE (DEBUG::MTC, string_compose ("MTCsync spd: %1 pos: %2 | last-pos: %3 | elapsed: %4\n",
|
|
||||||
speed, pos, last.position, (now - last.timestamp)));
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Timecode::TimecodeFormat
|
Timecode::TimecodeFormat
|
||||||
MTC_TransportMaster::apparent_timecode_format () const
|
MTC_TransportMaster::apparent_timecode_format () const
|
||||||
{
|
{
|
||||||
|
@ -1119,8 +1119,9 @@ Session::start_locate (samplepos_t target_sample, bool with_roll, bool with_flus
|
|||||||
|
|
||||||
double sp;
|
double sp;
|
||||||
samplepos_t pos;
|
samplepos_t pos;
|
||||||
|
samplepos_t ignore1, ignore2;
|
||||||
|
|
||||||
transport_master()->speed_and_position (sp, pos, 0);
|
transport_master()->speed_and_position (sp, pos, ignore1, ignore2, 0);
|
||||||
|
|
||||||
if (target_sample != pos) {
|
if (target_sample != pos) {
|
||||||
|
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
#include "pbd/debug.h"
|
#include "pbd/debug.h"
|
||||||
|
|
||||||
#include "ardour/audioengine.h"
|
#include "ardour/audioengine.h"
|
||||||
|
#include "ardour/debug.h"
|
||||||
#include "ardour/midi_port.h"
|
#include "ardour/midi_port.h"
|
||||||
#include "ardour/session.h"
|
#include "ardour/session.h"
|
||||||
#include "ardour/transport_master.h"
|
#include "ardour/transport_master.h"
|
||||||
@ -84,6 +85,59 @@ TransportMaster::~TransportMaster()
|
|||||||
delete _session;
|
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 > labs (seekahead_distance())) {
|
||||||
|
/* 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 for 2 samples - reset pending, pos = %2\n", name(), 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
|
void
|
||||||
TransportMaster::register_properties ()
|
TransportMaster::register_properties ()
|
||||||
{
|
{
|
||||||
|
@ -175,8 +175,9 @@ TransportMasterManager::pre_process_transport_masters (pframes_t nframes, sample
|
|||||||
}
|
}
|
||||||
|
|
||||||
double engine_speed;
|
double engine_speed;
|
||||||
|
samplepos_t ignore1, ignore2;
|
||||||
|
|
||||||
if (!_current_master->speed_and_position (_master_speed, _master_position, now)) {
|
if (!_current_master->speed_and_position (_master_speed, _master_position, ignore1, ignore2, now)) {
|
||||||
return 1.0;
|
return 1.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user