7a6d6a6ed6f481e0d931ec0ed8526cb93eb45266
[ardour.git] / libs / ardour / mtc_slave.cc
1 /*
2     Copyright (C) 2002-4 Paul Davis
3     Overhaul 2012 Robin Gareus <robin@gareus.org>
4
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14
15     You should have received a copy of the GNU General Public License
16     along with this program; if not, write to the Free Software
17     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18
19 */
20 #include <iostream>
21 #include <errno.h>
22 #include <sys/types.h>
23 #include <unistd.h>
24
25 #include "pbd/error.h"
26 #include "pbd/pthread_utils.h"
27
28 #include "ardour/audioengine.h"
29 #include "ardour/debug.h"
30 #include "ardour/midi_buffer.h"
31 #include "ardour/midi_port.h"
32 #include "ardour/session.h"
33 #include "ardour/transport_master.h"
34
35 #include <glibmm/timer.h>
36
37 #include "pbd/i18n.h"
38
39 using namespace std;
40 using namespace ARDOUR;
41 using namespace MIDI;
42 using namespace PBD;
43 using namespace Timecode;
44
45 /* length (in timecode frames) of the "window" that we consider legal given receipt of
46    a given timecode position. Ardour will try to chase within this window, and will
47    stop+locate+wait+chase if timecode arrives outside of it. The window extends entirely
48    in the current direction of motion, so if any timecode arrives that is before the most
49    recently received position (and without the direction of timecode reversing too), we
50    will stop+locate+wait+chase.
51 */
52 const int MTC_TransportMaster::sample_tolerance = 2;
53
54 MTC_TransportMaster::MTC_TransportMaster (std::string const & name)
55         : TimecodeTransportMaster (name, MTC)
56         , can_notify_on_unknown_rate (true)
57         , mtc_frame (0)
58         , mtc_frame_dll (0)
59         , last_inbound_frame (0)
60         , window_begin (0)
61         , window_end (0)
62         , first_mtc_timestamp (0)
63         , did_reset_tc_format (false)
64         , reset_pending (0)
65         , reset_position (false)
66         , transport_direction (1)
67         , busy_guard1 (0)
68         , busy_guard2 (0)
69         , printed_timecode_warning (false)
70 {
71         if ((_port = create_midi_port (string_compose ("%1 in", name))) == 0) {
72                 throw failed_constructor();
73         }
74
75         DEBUG_TRACE (DEBUG::Slave, string_compose ("MTC registered %1\n", _port->name()));
76
77         init ();
78 }
79
80 MTC_TransportMaster::~MTC_TransportMaster()
81 {
82         port_connections.drop_connections();
83         config_connection.disconnect();
84
85         while (busy_guard1 != busy_guard2) {
86                 /* make sure MIDI parser is not currently calling any callbacks in here,
87                  * else there's a segfault ahead!
88                  *
89                  * XXX this is called from jack rt-context :(
90                  * TODO fix libs/ardour/session_transport.cc:1321 (delete _slave;)
91                  */
92                 sched_yield();
93         }
94
95         if (did_reset_tc_format) {
96                 _session->config.set_timecode_format (saved_tc_format);
97         }
98 }
99
100 void
101 MTC_TransportMaster::init ()
102 {
103         reset (true);
104 }
105
106 void
107 MTC_TransportMaster::set_session (Session *s)
108 {
109         config_connection.disconnect ();
110         port_connections.drop_connections();
111
112         _session = s;
113
114         if (_session) {
115
116                 last_mtc_fps_byte = _session->get_mtc_timecode_bits ();
117                 quarter_frame_duration = (double) (_session->samples_per_timecode_frame() / 4.0);
118                 mtc_timecode = _session->config.get_timecode_format();
119                 a3e_timecode = _session->config.get_timecode_format();
120
121                 parse_timecode_offset ();
122                 reset (true);
123
124                 parser.mtc_time.connect_same_thread (port_connections,  boost::bind (&MTC_TransportMaster::update_mtc_time, this, _1, _2, _3));
125                 parser.mtc_qtr.connect_same_thread (port_connections, boost::bind (&MTC_TransportMaster::update_mtc_qtr, this, _1, _2, _3));
126                 parser.mtc_status.connect_same_thread (port_connections, boost::bind (&MTC_TransportMaster::update_mtc_status, this, _1));
127
128                 _session->config.ParameterChanged.connect_same_thread (config_connection, boost::bind (&MTC_TransportMaster::parameter_changed, this, _1));
129         }
130 }
131
132 void
133 MTC_TransportMaster::pre_process (MIDI::pframes_t nframes, samplepos_t now, boost::optional<samplepos_t> session_pos)
134 {
135         /* Read and parse incoming MIDI */
136
137         _midi_port->read_and_parse_entire_midi_buffer_with_no_speed_adjustment (nframes, parser, now);
138
139         if (session_pos) {
140                 const samplepos_t current_pos = current.position + ((now - current.timestamp) * current.speed);
141                 _current_delta = current_pos - *session_pos;
142         } else {
143                 _current_delta = 0;
144         }
145 }
146
147 void
148 MTC_TransportMaster::parse_timecode_offset() {
149         Timecode::Time offset_tc;
150         Timecode::parse_timecode_format (_session->config.get_slave_timecode_offset(), offset_tc);
151         offset_tc.rate = _session->timecode_frames_per_second();
152         offset_tc.drop = _session->timecode_drop_frames();
153         _session->timecode_to_sample(offset_tc, timecode_offset, false, false);
154         timecode_negative_offset = offset_tc.negative;
155 }
156
157 void
158 MTC_TransportMaster::parameter_changed (std::string const & p)
159 {
160         if (p == "slave-timecode-offset"
161                         || p == "timecode-format"
162                         ) {
163                 parse_timecode_offset();
164         }
165 }
166
167 ARDOUR::samplecnt_t
168 MTC_TransportMaster::resolution () const
169 {
170         return (samplecnt_t) quarter_frame_duration * 4.0;
171 }
172
173 ARDOUR::samplecnt_t
174 MTC_TransportMaster::seekahead_distance () const
175 {
176         return quarter_frame_duration * 8 * transport_direction;
177 }
178
179 bool
180 MTC_TransportMaster::outside_window (samplepos_t pos) const
181 {
182         return ((pos < window_begin) || (pos > window_end));
183 }
184
185
186 bool
187 MTC_TransportMaster::locked () const
188 {
189         DEBUG_TRACE (DEBUG::MTC, string_compose ("locked ? %1 last %2\n", parser.mtc_locked(), last_inbound_frame));
190         return parser.mtc_locked() && last_inbound_frame !=0;
191 }
192
193 bool
194 MTC_TransportMaster::ok() const
195 {
196         return true;
197 }
198
199 void
200 MTC_TransportMaster::queue_reset (bool reset_pos)
201 {
202         Glib::Threads::Mutex::Lock lm (reset_lock);
203         reset_pending++;
204         if (reset_pos) {
205                 reset_position = true;
206         }
207 }
208
209 void
210 MTC_TransportMaster::maybe_reset ()
211 {
212         Glib::Threads::Mutex::Lock lm (reset_lock);
213
214         if (reset_pending) {
215                 reset (reset_position);
216                 reset_pending = 0;
217                 reset_position = false;
218         }
219 }
220
221 void
222 MTC_TransportMaster::reset (bool with_position)
223 {
224         DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC_TransportMaster reset %1\n", with_position?"with position":"without position"));
225
226         if (with_position) {
227                 last_inbound_frame = 0;
228                 current.guard1++;
229                 current.position = 0;
230                 current.timestamp = 0;
231                 current.speed = 0;
232                 current.guard2++;
233         } else {
234                 last_inbound_frame = 0;
235                 current.guard1++;
236                 current.timestamp = 0;
237                 current.speed = 0;
238                 current.guard2++;
239         }
240         first_mtc_timestamp = 0;
241         window_begin = 0;
242         window_end = 0;
243         transport_direction = 1;
244         _current_delta = 0;
245 }
246
247 void
248 MTC_TransportMaster::handle_locate (const MIDI::byte* mmc_tc)
249 {
250         MIDI::byte mtc[5];
251         DEBUG_TRACE (DEBUG::MTC, "MTC_TransportMaster::handle_locate\n");
252
253         mtc[4] = last_mtc_fps_byte;
254         mtc[3] = mmc_tc[0] & 0xf; /* hrs only */
255         mtc[2] = mmc_tc[1];
256         mtc[1] = mmc_tc[2];
257         mtc[0] = mmc_tc[3];
258
259         update_mtc_time (mtc, true, 0);
260 }
261
262 void
263 MTC_TransportMaster::read_current (SafeTime *st) const
264 {
265         int tries = 0;
266
267         do {
268                 if (tries == 10) {
269                         error << _("MTC Slave: atomic read of current time failed, sleeping!") << endmsg;
270                         Glib::usleep (20);
271                         tries = 0;
272                 }
273                 *st = current;
274                 tries++;
275
276         } while (st->guard1.load (boost::memory_order_acquire) != st->guard2.load (boost::memory_order_acquire));
277 }
278
279 void
280 MTC_TransportMaster::init_mtc_dll(samplepos_t tme, double qtr)
281 {
282         const double omega = 2.0 * M_PI * qtr / 2.0 / double(_session->sample_rate());
283         b = 1.4142135623730950488 * omega;
284         c = omega * omega;
285
286         e2 = qtr;
287         t0 = double(tme);
288         t1 = t0 + e2;
289         DEBUG_TRACE (DEBUG::MTC, string_compose ("[re-]init MTC DLL %1 %2 %3\n", t0, t1, e2));
290 }
291
292 /* called from MIDI parser */
293 void
294 MTC_TransportMaster::update_mtc_qtr (Parser& p, int which_qtr, samplepos_t now)
295 {
296         busy_guard1++;
297         const double qtr_d = quarter_frame_duration;
298
299         mtc_frame_dll += qtr_d * (double) transport_direction;
300         mtc_frame = rint(mtc_frame_dll);
301
302         DEBUG_TRACE (DEBUG::MTC, string_compose ("qtr sample %1 at %2 -> mtc_frame: %3\n", which_qtr, now, mtc_frame));
303
304         double mtc_speed = 0;
305         if (first_mtc_timestamp != 0) {
306                 /* update MTC DLL and calculate speed */
307                 const double e = mtc_frame_dll - (double)transport_direction * ((double)now - (double)current.timestamp + t0);
308                 t0 = t1;
309                 t1 += b * e + e2;
310                 e2 += c * e;
311
312                 mtc_speed = (t1 - t0) / qtr_d;
313                 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));
314
315                 current.update (mtc_frame, now, mtc_speed);
316
317                 last_inbound_frame = now;
318         }
319
320         maybe_reset ();
321
322         busy_guard2++;
323 }
324
325 /* called from MIDI parser _after_ update_mtc_qtr()
326  * when a full TC has been received
327  * OR on locate */
328 void
329 MTC_TransportMaster::update_mtc_time (const MIDI::byte *msg, bool was_full, samplepos_t now)
330 {
331         busy_guard1++;
332
333         /* "now" can be zero if this is called from a context where we do not have or do not want
334            to use a timestamp indicating when this MTC time was received. example: when we received
335            a locate command via MMC.
336         */
337         DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC::update_mtc_time - TID:%1\n", pthread_name()));
338         TimecodeFormat tc_format;
339         bool reset_tc = true;
340
341         timecode.hours = msg[3];
342         timecode.minutes = msg[2];
343         timecode.seconds = msg[1];
344         timecode.frames = msg[0];
345
346         last_mtc_fps_byte = msg[4];
347
348         DEBUG_TRACE (DEBUG::MTC, string_compose ("full mtc time known at %1, full ? %2\n", now, was_full));
349
350         if (now) {
351                 maybe_reset ();
352         }
353
354         switch (msg[4]) {
355         case MTC_24_FPS:
356                 timecode.rate = 24;
357                 timecode.drop = false;
358                 tc_format = timecode_24;
359                 can_notify_on_unknown_rate = true;
360                 break;
361         case MTC_25_FPS:
362                 timecode.rate = 25;
363                 timecode.drop = false;
364                 tc_format = timecode_25;
365                 can_notify_on_unknown_rate = true;
366                 break;
367         case MTC_30_FPS_DROP:
368                 if (fr2997()) {
369                         tc_format = Timecode::timecode_2997000drop;
370                         timecode.rate = (29970.0/1000.0);
371                 } else {
372                         tc_format = timecode_2997drop;
373                         timecode.rate = (30000.0/1001.0);
374                 }
375                 timecode.drop = true;
376                 can_notify_on_unknown_rate = true;
377                 break;
378         case MTC_30_FPS:
379                 timecode.rate = 30;
380                 timecode.drop = false;
381                 can_notify_on_unknown_rate = true;
382                 tc_format = timecode_30;
383                 break;
384         default:
385                 /* throttle error messages about unknown MTC rates */
386                 if (can_notify_on_unknown_rate) {
387                         error << string_compose (_("Unknown rate/drop value %1 in incoming MTC stream, session values used instead"),
388                                                  (int) msg[4])
389                               << endmsg;
390                         can_notify_on_unknown_rate = false;
391                 }
392                 timecode.rate = _session->timecode_frames_per_second();
393                 timecode.drop = _session->timecode_drop_frames();
394                 reset_tc = false;
395         }
396
397         if (reset_tc) {
398                 TimecodeFormat cur_timecode = _session->config.get_timecode_format();
399                 if (Config->get_timecode_sync_frame_rate()) {
400                         /* enforce time-code */
401                         if (!did_reset_tc_format) {
402                                 saved_tc_format = cur_timecode;
403                                 did_reset_tc_format = true;
404                         }
405                         if (cur_timecode != tc_format) {
406                                 if (ceil(Timecode::timecode_to_frames_per_second(cur_timecode)) != ceil(Timecode::timecode_to_frames_per_second(tc_format))) {
407                                         warning << string_compose(_("Session framerate adjusted from %1 TO: MTC's %2."),
408                                                         Timecode::timecode_format_name(cur_timecode),
409                                                         Timecode::timecode_format_name(tc_format))
410                                                 << endmsg;
411                                 }
412                         }
413                         _session->config.set_timecode_format (tc_format);
414                 } else {
415                         /* only warn about TC mismatch */
416                         if (mtc_timecode != tc_format) printed_timecode_warning = false;
417                         if (a3e_timecode != cur_timecode) printed_timecode_warning = false;
418
419                         if (cur_timecode != tc_format && ! printed_timecode_warning) {
420                                 if (ceil(Timecode::timecode_to_frames_per_second(cur_timecode)) != ceil(Timecode::timecode_to_frames_per_second(tc_format))) {
421                                         warning << string_compose(_("Session and MTC framerate mismatch: MTC:%1 %2:%3."),
422                                                                   Timecode::timecode_format_name(tc_format),
423                                                                   PROGRAM_NAME,
424                                                                   Timecode::timecode_format_name(cur_timecode))
425                                                 << endmsg;
426                                 }
427                                 printed_timecode_warning = true;
428                         }
429                 }
430                 mtc_timecode = tc_format;
431                 a3e_timecode = cur_timecode;
432
433                 speedup_due_to_tc_mismatch = timecode.rate / Timecode::timecode_to_frames_per_second(a3e_timecode);
434         }
435
436         /* do a careful conversion of the timecode value to a position
437            so that we take drop/nondrop and all that nonsense into
438            consideration.
439         */
440
441         quarter_frame_duration = (double(_session->sample_rate()) / (double) timecode.rate / 4.0);
442
443         Timecode::timecode_to_sample (timecode, mtc_frame, true, false,
444                 double(_session->sample_rate()),
445                 _session->config.get_subframes_per_frame(),
446                 timecode_negative_offset, timecode_offset
447                 );
448
449         DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC at %1 TC %2 = mtc_frame %3 (from full message ? %4) tc-ratio %5\n",
450                                                  now, timecode, mtc_frame, was_full, speedup_due_to_tc_mismatch));
451
452         if (was_full || outside_window (mtc_frame)) {
453                 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));
454                 _session->set_requested_return_sample (-1);
455                 _session->request_transport_speed (0, TRS_MTC);
456                 _session->request_locate (mtc_frame, false, TRS_MTC);
457                 update_mtc_status (MIDI::MTC_Stopped);
458                 reset (false);
459                 reset_window (mtc_frame);
460         } else {
461
462                 /* we've had the first set of 8 qtr sample messages, determine position
463                    and allow continuing qtr sample messages to provide position
464                    and speed information.
465                 */
466
467                 /* We received the last quarter frame 7 quarter frames (1.75 mtc
468                    samples) after the instance when the contents of the mtc quarter
469                    samples were decided. Add time to compensate for the elapsed 1.75
470                    samples.
471                 */
472                 double qtr = quarter_frame_duration;
473                 long int mtc_off = (long) rint(7.0 * qtr);
474
475                 DEBUG_TRACE (DEBUG::MTC, string_compose ("new mtc_frame: %1 | MTC-FpT: %2 A3-FpT:%3\n",
476                                                          mtc_frame, (4.0*qtr), _session->samples_per_timecode_frame()));
477
478                 switch (parser.mtc_running()) {
479                 case MTC_Backward:
480                         mtc_frame -= mtc_off;
481                         qtr *= -1.0;
482                         break;
483                 case MTC_Forward:
484                         mtc_frame += mtc_off;
485                         break;
486                 default:
487                         break;
488                 }
489
490                 DEBUG_TRACE (DEBUG::MTC, string_compose ("new mtc_frame (w/offset) = %1\n", mtc_frame));
491
492                 if (now) {
493                         if (first_mtc_timestamp == 0 || current.timestamp == 0) {
494                                 first_mtc_timestamp = now;
495                                 init_mtc_dll(mtc_frame, qtr);
496                                 mtc_frame_dll = mtc_frame;
497                         }
498                         current.update (mtc_frame, now, current.speed);
499                         reset_window (mtc_frame);
500                 }
501         }
502
503         if (now) {
504                 last_inbound_frame = now;
505         }
506         busy_guard2++;
507 }
508
509 void
510 MTC_TransportMaster::update_mtc_status (MIDI::MTC_Status status)
511 {
512         /* XXX !!! thread safety ... called from MIDI I/O context
513          * on locate (via ::update_mtc_time())
514          */
515         DEBUG_TRACE (DEBUG::MTC, string_compose("MTC_TransportMaster::update_mtc_status - TID:%1 MTC:%2\n", pthread_name(), mtc_frame));
516         return; // why was this fn needed anyway ? it just messes up things -> use reset.
517         busy_guard1++;
518
519         switch (status) {
520         case MTC_Stopped:
521                 current.update (mtc_frame, 0, 0);
522                 break;
523
524         case MTC_Forward:
525                 current.update (mtc_frame, 0, 0);
526                 break;
527
528         case MTC_Backward:
529                 current.update (mtc_frame, 0, 0);
530                 break;
531         }
532         busy_guard2++;
533 }
534
535 void
536 MTC_TransportMaster::reset_window (samplepos_t root)
537 {
538         /* if we're waiting for the master to catch us after seeking ahead, keep the window
539            of acceptable MTC samples wide open. otherwise, shrink it down to just 2 video frames
540            ahead of the window root (taking direction into account).
541         */
542
543         samplecnt_t const d = (quarter_frame_duration * 4 * sample_tolerance);
544
545         switch (parser.mtc_running()) {
546         case MTC_Forward:
547                 window_begin = root;
548                 transport_direction = 1;
549                 window_end = root + d;
550                 break;
551
552         case MTC_Backward:
553                 transport_direction = -1;
554                 if (root > d) {
555                         window_begin = root - d;
556                         window_end = root;
557                 } else {
558                         window_begin = 0;
559                 }
560                 window_end = root;
561                 break;
562
563         default:
564                 /* do nothing */
565                 break;
566         }
567
568         DEBUG_TRACE (DEBUG::MTC, string_compose ("reset MTC window @ %3, now %1 .. %2\n", window_begin, window_end, root));
569 }
570
571 /* main entry point from session_process.cc
572 xo * in process callback context */
573 bool
574 MTC_TransportMaster::speed_and_position (double& speed, samplepos_t& pos, samplepos_t now)
575 {
576         SafeTime last;
577
578         if (!_collect) {
579                 return false;
580         }
581
582         read_current (&last);
583
584         DEBUG_TRACE (DEBUG::MTC, string_compose ("speed&pos: timestamp %1 speed %2 dir %4 now %5 last-in %6\n",
585                                                  last.timestamp,
586                                                  last.speed,
587                                                  transport_direction,
588                                                  now,
589                                                  last_inbound_frame));
590
591         if (last.timestamp == 0) {
592                 return false;
593         }
594
595         if (last_inbound_frame && now > last_inbound_frame && now - last_inbound_frame > labs(seekahead_distance())) {
596                 /* no timecode for two cycles - conclude that it's stopped */
597
598                 if (!Config->get_transport_masters_just_roll_when_sync_lost()) {
599                         speed = 0;
600                         pos = last.position;
601                         _current_delta = 0;
602                         queue_reset (false);
603                         DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC not seen for 2 samples - reset pending, pos = %1\n", pos));
604                         return false;
605                 }
606         }
607
608
609         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));
610
611         speed = last.speed;
612
613         /* provide a .1% deadzone to lock the speed */
614         if (fabs (speed - 1.0) <= 0.001) {
615                 speed = 1.0;
616         }
617
618         pos =  last.position;
619         pos += (now - last.timestamp) * speed;
620
621         DEBUG_TRACE (DEBUG::MTC, string_compose ("MTCsync spd: %1 pos: %2 | last-pos: %3 | elapsed: %4\n",
622                                                  speed, pos, last.position, (now - last.timestamp)));
623
624         return true;
625 }
626
627 Timecode::TimecodeFormat
628 MTC_TransportMaster::apparent_timecode_format () const
629 {
630         return mtc_timecode;
631 }
632
633 std::string
634 MTC_TransportMaster::position_string() const
635 {
636         SafeTime last;
637         read_current (&last);
638         if (last.timestamp == 0 || reset_pending) {
639                 return " --:--:--:--";
640         }
641         return Timecode::timecode_format_sampletime(
642                 last.position,
643                 double(_session->sample_rate()),
644                 Timecode::timecode_to_frames_per_second(mtc_timecode),
645                 Timecode::timecode_has_drop_frames(mtc_timecode));
646 }
647
648 std::string
649 MTC_TransportMaster::delta_string () const
650 {
651         char delta[80];
652         SafeTime last;
653         read_current (&last);
654
655         delta[0] = '\0';
656
657         if (last.timestamp == 0 || reset_pending) {
658                 snprintf(delta, sizeof(delta), "\u2012\u2012\u2012\u2012");
659         } else {
660                 snprintf(delta, sizeof(delta), "\u0394<span foreground=\"green\" face=\"monospace\" >%s%s%" PRIi64 "</span>sm",
661                                 LEADINGZERO(abs(_current_delta)), PLUSMINUS(-_current_delta), abs(_current_delta));
662         }
663         return std::string(delta);
664 }