Set timecode format from active master only

This commit is contained in:
Robin Gareus 2020-05-13 16:08:48 +02:00
parent 5120b650c5
commit 7289be59c9
Signed by: rgareus
GPG Key ID: A090BCE02CF57F04
6 changed files with 96 additions and 134 deletions

View File

@ -474,8 +474,10 @@ public:
TimecodeTransportMaster (std::string const& name, SyncSource type);
virtual Timecode::TimecodeFormat apparent_timecode_format () const = 0;
samplepos_t timecode_offset;
bool timecode_negative_offset;
bool apparent_timecode_format_valid () const {
return timecode_format_valid;
}
bool fr2997 () const
{
@ -486,6 +488,10 @@ public:
protected:
void register_properties ();
samplepos_t timecode_offset;
bool timecode_negative_offset;
bool timecode_format_valid;
private:
PBD::Property<bool> _fr2997;
};
@ -536,8 +542,7 @@ private:
samplepos_t window_begin;
samplepos_t window_end;
samplepos_t first_mtc_timestamp;
bool did_reset_tc_format;
Timecode::TimecodeFormat saved_tc_format;
Glib::Threads::Mutex reset_lock;
uint32_t reset_pending;
bool reset_position;
@ -545,12 +550,9 @@ private:
int busy_guard1;
int busy_guard2;
double speedup_due_to_tc_mismatch;
double quarter_frame_duration;
Timecode::TimecodeFormat mtc_timecode;
Timecode::TimecodeFormat a3e_timecode;
Timecode::Time timecode;
bool printed_timecode_warning;
void queue_reset (bool with_pos);
void maybe_reset ();
@ -616,26 +618,20 @@ private:
void parameter_changed (std::string const& p);
void connection_handler (boost::weak_ptr<ARDOUR::Port>, std::string, boost::weak_ptr<ARDOUR::Port>, std::string, bool);
bool did_reset_tc_format;
Timecode::TimecodeFormat saved_tc_format;
LTCDecoder* decoder;
double samples_per_ltc_frame;
Timecode::Time timecode;
LTCFrameExt prev_frame;
bool fps_detected;
samplecnt_t monotonic_cnt;
uint64_t frames_since_reset;
int delayedlocked;
samplecnt_t monotonic_cnt;
uint64_t frames_since_reset;
int delayedlocked;
int ltc_detect_fps_cnt;
int ltc_detect_fps_max;
bool printed_timecode_warning;
bool sync_lock_broken;
Timecode::TimecodeFormat ltc_timecode;
Timecode::TimecodeFormat a3e_timecode;
double samples_per_timecode_frame;
int ltc_detect_fps_cnt;
int ltc_detect_fps_max;
bool sync_lock_broken;
double samples_per_timecode_frame;
PBD::ScopedConnection port_connection;
PBD::ScopedConnectionList session_connections;

View File

@ -96,26 +96,32 @@ class LIBARDOUR_API TransportMasterManager : public boost::noncopyable
mutable Glib::Threads::RWLock lock;
double _master_speed;
samplepos_t _master_position;
boost::shared_ptr<TransportMaster> _current_master;
boost::shared_ptr<TransportMaster> _current_master;
Session* _session;
bool _master_invalid_this_cycle;
bool disk_output_blocked;
// a DLL to chase the transport master
int transport_dll_initstate;
double t0; /// time at the beginning of ???
double t1; /// calculated end of the ???
double e2; /// second order loop error
double bandwidth; /// DLL filter bandwidth
double b, c, omega; /// DLL filter coefficients
/* a DLL to chase the transport master, calculate playback speed
* by matching Ardour's current playhead position against
* the position of the transport-master */
double t0; // PH position at the beginning of this cycle
double t1; // expected PH position if next cycle
double e2; // second order loop error
double bandwidth; // DLL filter bandwidth
double b, c, omega; // DLL filter coefficients
void init_transport_master_dll (double speed, samplepos_t pos);
int master_dll_initstate;
int master_dll_initstate; // play-direction -1, +1, or 0: not initialized
static TransportMasterManager* _instance;
/* original TC format in case the slave changed it */
boost::optional<Timecode::TimecodeFormat> _session_tc_format;
void maybe_restore_tc_format ();
void maybe_set_tc_format ();
int add_locked (boost::shared_ptr<TransportMaster>);
double compute_matching_master_speed (pframes_t nframes, samplepos_t, bool& locate_required);
int set_current_locked (boost::shared_ptr<TransportMaster>);

View File

@ -48,8 +48,6 @@ using namespace Timecode;
LTC_TransportMaster::LTC_TransportMaster (std::string const & name)
: TimecodeTransportMaster (name, LTC)
, did_reset_tc_format (false)
, saved_tc_format (timecode_24) // whatever ....
, decoder (0)
, samples_per_ltc_frame (0)
, fps_detected (false)
@ -58,10 +56,7 @@ LTC_TransportMaster::LTC_TransportMaster (std::string const & name)
, delayedlocked (10)
, ltc_detect_fps_cnt (0)
, ltc_detect_fps_max (0)
, printed_timecode_warning (false)
, sync_lock_broken (false)
, ltc_timecode (Timecode::timecode_24)
, a3e_timecode (Timecode::timecode_24)
, samples_per_timecode_frame (0)
{
memset (&prev_frame, 0, sizeof(LTCFrameExt));
@ -94,9 +89,6 @@ LTC_TransportMaster::set_session (Session *s)
samples_per_ltc_frame = _session->samples_per_timecode_frame();
timecode.drop = _session->timecode_drop_frames();
printed_timecode_warning = false;
ltc_timecode = _session->config.get_timecode_format();
a3e_timecode = _session->config.get_timecode_format();
if (decoder) {
ltc_decoder_free (decoder);
@ -117,10 +109,6 @@ LTC_TransportMaster::~LTC_TransportMaster()
port_connection.disconnect();
session_connections.drop_connections();
if (did_reset_tc_format) {
_session->config.set_timecode_format (saved_tc_format);
}
ltc_decoder_free(decoder);
}
@ -234,6 +222,7 @@ LTC_TransportMaster::reset (bool with_position)
monotonic_cnt = 0;
memset (&prev_frame, 0, sizeof(LTCFrameExt));
frames_since_reset = 0;
timecode_format_valid = false;
}
void
@ -358,6 +347,8 @@ LTC_TransportMaster::detect_ltc_fps(int frameno, bool df)
}
}
timecode_format_valid = true; /* SET FLAG */
if (timecode.rate != detected_fps || timecode.drop != df) {
DEBUG_TRACE (DEBUG::LTC, string_compose ("detected FPS: %1%2\n", detected_fps, df?"df":"ndf"));
} else {
@ -378,50 +369,7 @@ LTC_TransportMaster::detect_ltc_fps(int frameno, bool df)
}
TimecodeFormat tc_format = apparent_timecode_format();
if (_session) {
/* poll and check session TC */
TimecodeFormat cur_timecode = _session->config.get_timecode_format();
if (Config->get_timecode_sync_frame_rate()) {
/* enforce time-code */
if (!did_reset_tc_format) {
saved_tc_format = cur_timecode;
did_reset_tc_format = true;
}
if (cur_timecode != tc_format) {
if (ceil(Timecode::timecode_to_frames_per_second(cur_timecode)) != ceil(Timecode::timecode_to_frames_per_second(tc_format))) {
warning << string_compose(_("Session framerate adjusted from %1 to LTC's %2."),
Timecode::timecode_format_name(cur_timecode),
Timecode::timecode_format_name(tc_format))
<< endmsg;
}
_session->config.set_timecode_format (tc_format);
}
} else {
/* only warn about TC mismatch */
if (ltc_timecode != tc_format) printed_timecode_warning = false;
if (a3e_timecode != cur_timecode) printed_timecode_warning = false;
if (cur_timecode != tc_format && ! printed_timecode_warning) {
if (ceil(Timecode::timecode_to_frames_per_second(cur_timecode)) != ceil(Timecode::timecode_to_frames_per_second(tc_format))) {
warning << string_compose(_("Session and LTC framerate mismatch: LTC:%1 Session:%2."),
Timecode::timecode_format_name(tc_format),
Timecode::timecode_format_name(cur_timecode))
<< endmsg;
}
printed_timecode_warning = true;
}
}
a3e_timecode = cur_timecode;
}
ltc_timecode = tc_format;
samples_per_timecode_frame = ENGINE->sample_rate() / Timecode::timecode_to_frames_per_second (ltc_timecode);
samples_per_timecode_frame = ENGINE->sample_rate() / Timecode::timecode_to_frames_per_second (tc_format);
return fps_changed;
}

View File

@ -61,13 +61,11 @@ MTC_TransportMaster::MTC_TransportMaster (std::string const & name)
, window_begin (0)
, window_end (0)
, first_mtc_timestamp (0)
, did_reset_tc_format (false)
, reset_pending (0)
, reset_position (false)
, transport_direction (1)
, busy_guard1 (0)
, busy_guard2 (0)
, printed_timecode_warning (false)
{
init ();
}
@ -76,10 +74,6 @@ MTC_TransportMaster::~MTC_TransportMaster()
{
port_connections.drop_connections();
session_connections.drop_connections();
if (_session && did_reset_tc_format) {
_session->config.set_timecode_format (saved_tc_format);
}
}
void
@ -135,7 +129,6 @@ MTC_TransportMaster::set_session (Session *s)
last_mtc_fps_byte = _session->get_mtc_timecode_bits ();
quarter_frame_duration = (double) (_session->samples_per_timecode_frame() / 4.0);
mtc_timecode = _session->config.get_timecode_format();
a3e_timecode = _session->config.get_timecode_format();
parse_timecode_offset ();
reset (true);
@ -265,6 +258,7 @@ MTC_TransportMaster::reset (bool with_position)
window_end = 0;
transport_direction = 1;
_current_delta = 0;
timecode_format_valid = false;
}
void
@ -342,7 +336,7 @@ MTC_TransportMaster::update_mtc_time (const MIDI::byte *msg, bool was_full, samp
*/
DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC::update_mtc_time - TID:%1\n", pthread_name()));
TimecodeFormat tc_format;
bool reset_tc = true;
bool have_tc = true;
timecode.hours = msg[3];
timecode.minutes = msg[2];
@ -397,46 +391,12 @@ MTC_TransportMaster::update_mtc_time (const MIDI::byte *msg, bool was_full, samp
}
timecode.rate = _session->timecode_frames_per_second();
timecode.drop = _session->timecode_drop_frames();
reset_tc = false;
have_tc = false;
}
if (reset_tc) {
TimecodeFormat cur_timecode = _session->config.get_timecode_format();
if (Config->get_timecode_sync_frame_rate()) {
/* enforce time-code */
if (!did_reset_tc_format) {
saved_tc_format = cur_timecode;
did_reset_tc_format = true;
}
if (cur_timecode != tc_format) {
if (ceil(Timecode::timecode_to_frames_per_second(cur_timecode)) != ceil(Timecode::timecode_to_frames_per_second(tc_format))) {
warning << string_compose(_("Session framerate adjusted from %1 TO: MTC's %2."),
Timecode::timecode_format_name(cur_timecode),
Timecode::timecode_format_name(tc_format))
<< endmsg;
}
}
_session->config.set_timecode_format (tc_format);
} else {
/* only warn about TC mismatch */
if (mtc_timecode != tc_format) printed_timecode_warning = false;
if (a3e_timecode != cur_timecode) printed_timecode_warning = false;
if (cur_timecode != tc_format && ! printed_timecode_warning) {
if (ceil(Timecode::timecode_to_frames_per_second(cur_timecode)) != ceil(Timecode::timecode_to_frames_per_second(tc_format))) {
warning << string_compose(_("Session and MTC framerate mismatch: MTC:%1 %2:%3."),
Timecode::timecode_format_name(tc_format),
PROGRAM_NAME,
Timecode::timecode_format_name(cur_timecode))
<< endmsg;
}
printed_timecode_warning = true;
}
}
if (have_tc) {
mtc_timecode = tc_format;
a3e_timecode = cur_timecode;
speedup_due_to_tc_mismatch = timecode.rate / Timecode::timecode_to_frames_per_second(a3e_timecode);
timecode_format_valid = true; /* SET FLAG */
}
/* do a careful conversion of the timecode value to a position
@ -452,8 +412,7 @@ MTC_TransportMaster::update_mtc_time (const MIDI::byte *msg, bool was_full, samp
timecode_negative_offset, timecode_offset
);
DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC at %1 TC %2 = mtc_frame %3 (from full message ? %4) tc-ratio %5\n",
now, timecode, mtc_frame, was_full, speedup_due_to_tc_mismatch));
DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC at %1 TC %2 = mtc_frame %3 (from full message ? %4)\n", now, timecode, mtc_frame, was_full));
if (was_full || outside_window (mtc_frame)) {
DEBUG_TRACE (DEBUG::MTC, string_compose ("update_mtc_time: full TC %1 or outside window %2 MTC %3\n", was_full, outside_window (mtc_frame), mtc_frame));

View File

@ -511,6 +511,9 @@ TransportMaster::set_request_mask (TransportRequestType t)
TimecodeTransportMaster::TimecodeTransportMaster (std::string const & name, SyncSource type)
: TransportMaster (type, name)
, timecode_offset (0)
, timecode_negative_offset (false)
, timecode_format_valid (false)
, _fr2997 (Properties::fr2997, false)
{
register_properties ();

View File

@ -102,6 +102,8 @@ TransportMasterManager::set_session (Session* s)
Glib::Threads::RWLock::ReaderLock lm (lock);
maybe_restore_tc_format ();
config_connection.disconnect ();
_session = s;
@ -177,6 +179,7 @@ TransportMasterManager::pre_process_transport_masters (pframes_t nframes, sample
}
if (!_session->config.get_external_sync()) {
maybe_restore_tc_format ();
DEBUG_TRACE (DEBUG::Slave, string_compose ("no external sync, use session actual speed of %1\n", _session->actual_speed() ? _session->actual_speed() : 1.0));
return _session->actual_speed () ? _session->actual_speed() : 1.0;
}
@ -231,7 +234,7 @@ TransportMasterManager::pre_process_transport_masters (pframes_t nframes, sample
if (master_dll_initstate == 0) {
init_transport_master_dll (_master_speed, _master_position);
DEBUG_TRACE (DEBUG::Slave, string_compose ("no roll3 - still initializing master DLL, will be %1 next process cycle\n", master_dll_initstate));
DEBUG_TRACE (DEBUG::Slave, string_compose ("initializing master DLL, will be %1 next process cycle\n", master_dll_initstate));
return _master_speed;
}
@ -298,11 +301,56 @@ TransportMasterManager::pre_process_transport_masters (pframes_t nframes, sample
_master_invalid_this_cycle = false;
maybe_set_tc_format ();
DEBUG_TRACE (DEBUG::Slave, string_compose ("computed resampling ratio as %1 with position = %2 and speed = %3\n", engine_speed, _master_position, _master_speed));
return engine_speed;
}
void
TransportMasterManager::maybe_restore_tc_format ()
{
if (_session && _session_tc_format) {
_session->config.set_timecode_format (*_session_tc_format);
}
_session_tc_format.reset ();
}
void
TransportMasterManager::maybe_set_tc_format ()
{
if (!Config->get_timecode_sync_frame_rate() || !_session) {
return;
}
boost::shared_ptr<TimecodeTransportMaster> tcm;
if ((tcm = boost::dynamic_pointer_cast<TimecodeTransportMaster>(_current_master)) == 0) {
return;
}
if (!tcm->apparent_timecode_format_valid ()) {
return;
}
Timecode::TimecodeFormat stf = _session->config.get_timecode_format();
Timecode::TimecodeFormat mtf = tcm->apparent_timecode_format ();
if (stf == mtf) {
return;
}
/* save session's original TC */
if (!_session_tc_format) {
_session_tc_format = stf;
}
warning << string_compose(_("Transport master adjusted framerate from %1 to %2."),
Timecode::timecode_format_name(stf),
Timecode::timecode_format_name(mtf))
<< endmsg;
_session->config.set_timecode_format (mtf);
}
void
TransportMasterManager::init_transport_master_dll (double speed, samplepos_t pos)
@ -423,6 +471,8 @@ TransportMasterManager::set_current_locked (boost::shared_ptr<TransportMaster> c
}
}
maybe_restore_tc_format ();
if (!c->usable()) {
return -1;
}