+ busy_guard1++;
+
+ /* "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. example: when we received
+ a locate command via MMC.
+ */
+
+ //DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC::update_mtc_time - TID:%1\n", ::pthread_self()));
+ TimecodeFormat tc_format;
+ bool reset_tc = true;
+
+ timecode.hours = msg[3];
+ timecode.minutes = msg[2];
+ timecode.seconds = msg[1];
+ timecode.frames = msg[0];
+
+ last_mtc_fps_byte = msg[4];
+
+ DEBUG_TRACE (DEBUG::MTC, string_compose ("full mtc time known at %1, full ? %2\n", now, was_full));
+
+ if (now) {
+ maybe_reset ();
+ }
+
+ switch (msg[4]) {
+ case MTC_24_FPS:
+ timecode.rate = 24;
+ timecode.drop = false;
+ tc_format = timecode_24;
+ can_notify_on_unknown_rate = true;
+ break;
+ case MTC_25_FPS:
+ timecode.rate = 25;
+ timecode.drop = false;
+ tc_format = timecode_25;
+ can_notify_on_unknown_rate = true;
+ break;
+ case MTC_30_FPS_DROP:
+ if (Config->get_timecode_source_2997()) {
+ tc_format = Timecode::timecode_2997000drop;
+ timecode.rate = (29970.0/1000.0);
+ } else {
+ tc_format = timecode_2997drop;
+ timecode.rate = (30000.0/1001.0);
+ }
+ timecode.drop = true;
+ can_notify_on_unknown_rate = true;
+ break;
+ case MTC_30_FPS:
+ timecode.rate = 30;
+ timecode.drop = false;
+ can_notify_on_unknown_rate = true;
+ tc_format = timecode_30;
+ break;
+ default:
+ /* throttle error messages about unknown MTC rates */
+ if (can_notify_on_unknown_rate) {
+ error << string_compose (_("Unknown rate/drop value %1 in incoming MTC stream, session values used instead"),
+ (int) msg[4])
+ << endmsg;
+ can_notify_on_unknown_rate = false;
+ }
+ timecode.rate = session.timecode_frames_per_second();
+ timecode.drop = session.timecode_drop_frames();
+ reset_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;
+ }
+ }
+ mtc_timecode = tc_format;
+ a3e_timecode = cur_timecode;
+
+ speedup_due_to_tc_mismatch = timecode.rate / Timecode::timecode_to_frames_per_second(a3e_timecode);
+ }
+
+ /* do a careful conversion of the timecode value to a position
+ so that we take drop/nondrop and all that nonsense into
+ consideration.
+ */
+
+ quarter_frame_duration = (double(session.frame_rate()) / (double) timecode.rate / 4.0);
+
+ Timecode::timecode_to_sample (timecode, mtc_frame, true, false,
+ double(session.frame_rate()),
+ session.config.get_subframes_per_frame(),
+ 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));
+
+ if (was_full || outside_window (mtc_frame)) {
+ DEBUG_TRACE (DEBUG::MTC, string_compose ("update_mtc_time: full TC or outside window. - TID:%1\n", ::pthread_self()));
+ session.request_locate (mtc_frame, false);
+ session.request_transport_speed (0);
+ update_mtc_status (MIDI::MTC_Stopped);
+ reset (false);
+ reset_window (mtc_frame);
+ } else {
+
+ /* we've had the first set of 8 qtr frame messages, determine position
+ and allow continuing qtr frame messages to provide position
+ and speed information.
+ */
+
+ /* We received the last quarter frame 7 quarter frames (1.75 mtc
+ frames) after the instance when the contents of the mtc quarter
+ frames were decided. Add time to compensate for the elapsed 1.75
+ frames.
+ */
+ double qtr = quarter_frame_duration;
+ long int mtc_off = (long) rint(7.0 * qtr);
+
+ DEBUG_TRACE (DEBUG::MTC, string_compose ("new mtc_frame: %1 | MTC-FpT: %2 A3-FpT:%3\n",
+ mtc_frame, (4.0*qtr), session.frames_per_timecode_frame()));
+
+ switch (port->parser()->mtc_running()) {
+ case MTC_Backward:
+ mtc_frame -= mtc_off;
+ qtr *= -1.0;
+ break;
+ case MTC_Forward:
+ mtc_frame += mtc_off;
+ break;
+ default:
+ break;
+ }
+
+ DEBUG_TRACE (DEBUG::MTC, string_compose ("new mtc_frame (w/offset) = %1\n", mtc_frame));
+
+ if (now) {
+ if (first_mtc_timestamp == 0 || current.timestamp == 0) {
+ first_mtc_timestamp = now;
+ init_mtc_dll(mtc_frame, qtr);
+ mtc_frame_dll = mtc_frame;
+ }
+ current.guard1++;
+ current.position = mtc_frame;
+ current.timestamp = now;
+ current.guard2++;
+ reset_window (mtc_frame);
+ }
+ }
+
+ if (now) {
+ last_inbound_frame = now;
+ }
+ busy_guard2++;
+}
+
+void
+MTC_Slave::update_mtc_status (MIDI::MTC_Status status)
+{
+ /* XXX !!! thread safety ... called from MIDI I/O context
+ * on locate (via ::update_mtc_time())
+ */
+ DEBUG_TRACE (DEBUG::MTC, string_compose("MTC_Slave::update_mtc_status - TID:%1\n", ::pthread_self()));
+ return; // why was this fn needed anyway ? it just messes up things -> use reset.
+ busy_guard1++;