new transport slave/master implementation, libs/ edition
[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 (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 != st->guard2);
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.guard1++;
316                 current.position = mtc_frame;
317                 current.timestamp = now;
318                 current.speed = mtc_speed;
319                 current.guard2++;
320
321                 last_inbound_frame = now;
322         }
323
324         maybe_reset ();
325
326         busy_guard2++;
327 }
328
329 /* called from MIDI parser _after_ update_mtc_qtr()
330  * when a full TC has been received
331  * OR on locate */
332 void
333 MTC_TransportMaster::update_mtc_time (const MIDI::byte *msg, bool was_full, samplepos_t now)
334 {
335         busy_guard1++;
336
337         /* "now" can be zero if this is called from a context where we do not have or do not want
338            to use a timestamp indicating when this MTC time was received. example: when we received
339            a locate command via MMC.
340         */
341         DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC::update_mtc_time - TID:%1\n", pthread_name()));
342         TimecodeFormat tc_format;
343         bool reset_tc = true;
344
345         timecode.hours = msg[3];
346         timecode.minutes = msg[2];
347         timecode.seconds = msg[1];
348         timecode.frames = msg[0];
349
350         last_mtc_fps_byte = msg[4];
351
352         DEBUG_TRACE (DEBUG::MTC, string_compose ("full mtc time known at %1, full ? %2\n", now, was_full));
353
354         if (now) {
355                 maybe_reset ();
356         }
357
358         switch (msg[4]) {
359         case MTC_24_FPS:
360                 timecode.rate = 24;
361                 timecode.drop = false;
362                 tc_format = timecode_24;
363                 can_notify_on_unknown_rate = true;
364                 break;
365         case MTC_25_FPS:
366                 timecode.rate = 25;
367                 timecode.drop = false;
368                 tc_format = timecode_25;
369                 can_notify_on_unknown_rate = true;
370                 break;
371         case MTC_30_FPS_DROP:
372                 if (fr2997()) {
373                         tc_format = Timecode::timecode_2997000drop;
374                         timecode.rate = (29970.0/1000.0);
375                 } else {
376                         tc_format = timecode_2997drop;
377                         timecode.rate = (30000.0/1001.0);
378                 }
379                 timecode.drop = true;
380                 can_notify_on_unknown_rate = true;
381                 break;
382         case MTC_30_FPS:
383                 timecode.rate = 30;
384                 timecode.drop = false;
385                 can_notify_on_unknown_rate = true;
386                 tc_format = timecode_30;
387                 break;
388         default:
389                 /* throttle error messages about unknown MTC rates */
390                 if (can_notify_on_unknown_rate) {
391                         error << string_compose (_("Unknown rate/drop value %1 in incoming MTC stream, session values used instead"),
392                                                  (int) msg[4])
393                               << endmsg;
394                         can_notify_on_unknown_rate = false;
395                 }
396                 timecode.rate = _session->timecode_frames_per_second();
397                 timecode.drop = _session->timecode_drop_frames();
398                 reset_tc = false;
399         }
400
401         if (reset_tc) {
402                 TimecodeFormat cur_timecode = _session->config.get_timecode_format();
403                 if (Config->get_timecode_sync_frame_rate()) {
404                         /* enforce time-code */
405                         if (!did_reset_tc_format) {
406                                 saved_tc_format = cur_timecode;
407                                 did_reset_tc_format = true;
408                         }
409                         if (cur_timecode != tc_format) {
410                                 if (ceil(Timecode::timecode_to_frames_per_second(cur_timecode)) != ceil(Timecode::timecode_to_frames_per_second(tc_format))) {
411                                         warning << string_compose(_("Session framerate adjusted from %1 TO: MTC's %2."),
412                                                         Timecode::timecode_format_name(cur_timecode),
413                                                         Timecode::timecode_format_name(tc_format))
414                                                 << endmsg;
415                                 }
416                         }
417                         _session->config.set_timecode_format (tc_format);
418                 } else {
419                         /* only warn about TC mismatch */
420                         if (mtc_timecode != tc_format) printed_timecode_warning = false;
421                         if (a3e_timecode != cur_timecode) printed_timecode_warning = false;
422
423                         if (cur_timecode != tc_format && ! printed_timecode_warning) {
424                                 if (ceil(Timecode::timecode_to_frames_per_second(cur_timecode)) != ceil(Timecode::timecode_to_frames_per_second(tc_format))) {
425                                         warning << string_compose(_("Session and MTC framerate mismatch: MTC:%1 %2:%3."),
426                                                                   Timecode::timecode_format_name(tc_format),
427                                                                   PROGRAM_NAME,
428                                                                   Timecode::timecode_format_name(cur_timecode))
429                                                 << endmsg;
430                                 }
431                                 printed_timecode_warning = true;
432                         }
433                 }
434                 mtc_timecode = tc_format;
435                 a3e_timecode = cur_timecode;
436
437                 speedup_due_to_tc_mismatch = timecode.rate / Timecode::timecode_to_frames_per_second(a3e_timecode);
438         }
439
440         /* do a careful conversion of the timecode value to a position
441            so that we take drop/nondrop and all that nonsense into
442            consideration.
443         */
444
445         quarter_frame_duration = (double(_session->sample_rate()) / (double) timecode.rate / 4.0);
446
447         Timecode::timecode_to_sample (timecode, mtc_frame, true, false,
448                 double(_session->sample_rate()),
449                 _session->config.get_subframes_per_frame(),
450                 timecode_negative_offset, timecode_offset
451                 );
452
453         DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC at %1 TC %2 = mtc_frame %3 (from full message ? %4) tc-ratio %5\n",
454                                                  now, timecode, mtc_frame, was_full, speedup_due_to_tc_mismatch));
455
456         if (was_full || outside_window (mtc_frame)) {
457                 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));
458                 _session->set_requested_return_sample (-1);
459                 _session->request_transport_speed (0, TRS_MTC);
460                 _session->request_locate (mtc_frame, false, TRS_MTC);
461                 update_mtc_status (MIDI::MTC_Stopped);
462                 reset (false);
463                 reset_window (mtc_frame);
464         } else {
465
466                 /* we've had the first set of 8 qtr sample messages, determine position
467                    and allow continuing qtr sample messages to provide position
468                    and speed information.
469                 */
470
471                 /* We received the last quarter frame 7 quarter frames (1.75 mtc
472                    samples) after the instance when the contents of the mtc quarter
473                    samples were decided. Add time to compensate for the elapsed 1.75
474                    samples.
475                 */
476                 double qtr = quarter_frame_duration;
477                 long int mtc_off = (long) rint(7.0 * qtr);
478
479                 DEBUG_TRACE (DEBUG::MTC, string_compose ("new mtc_frame: %1 | MTC-FpT: %2 A3-FpT:%3\n",
480                                                          mtc_frame, (4.0*qtr), _session->samples_per_timecode_frame()));
481
482                 switch (parser.mtc_running()) {
483                 case MTC_Backward:
484                         mtc_frame -= mtc_off;
485                         qtr *= -1.0;
486                         break;
487                 case MTC_Forward:
488                         mtc_frame += mtc_off;
489                         break;
490                 default:
491                         break;
492                 }
493
494                 DEBUG_TRACE (DEBUG::MTC, string_compose ("new mtc_frame (w/offset) = %1\n", mtc_frame));
495
496                 if (now) {
497                         if (first_mtc_timestamp == 0 || current.timestamp == 0) {
498                                 first_mtc_timestamp = now;
499                                 init_mtc_dll(mtc_frame, qtr);
500                                 mtc_frame_dll = mtc_frame;
501                         }
502                         current.guard1++;
503                         current.position = mtc_frame;
504                         current.timestamp = now;
505                         current.guard2++;
506                         reset_window (mtc_frame);
507                 }
508         }
509
510         if (now) {
511                 last_inbound_frame = now;
512         }
513         busy_guard2++;
514 }
515
516 void
517 MTC_TransportMaster::update_mtc_status (MIDI::MTC_Status status)
518 {
519         /* XXX !!! thread safety ... called from MIDI I/O context
520          * on locate (via ::update_mtc_time())
521          */
522         DEBUG_TRACE (DEBUG::MTC, string_compose("MTC_TransportMaster::update_mtc_status - TID:%1 MTC:%2\n", pthread_name(), mtc_frame));
523         return; // why was this fn needed anyway ? it just messes up things -> use reset.
524         busy_guard1++;
525
526         switch (status) {
527         case MTC_Stopped:
528                 current.guard1++;
529                 current.position = mtc_frame;
530                 current.timestamp = 0;
531                 current.speed = 0;
532                 current.guard2++;
533
534                 break;
535
536         case MTC_Forward:
537                 current.guard1++;
538                 current.position = mtc_frame;
539                 current.timestamp = 0;
540                 current.speed = 0;
541                 current.guard2++;
542                 break;
543
544         case MTC_Backward:
545                 current.guard1++;
546                 current.position = mtc_frame;
547                 current.timestamp = 0;
548                 current.speed = 0;
549                 current.guard2++;
550                 break;
551         }
552         busy_guard2++;
553 }
554
555 void
556 MTC_TransportMaster::reset_window (samplepos_t root)
557 {
558         /* if we're waiting for the master to catch us after seeking ahead, keep the window
559            of acceptable MTC samples wide open. otherwise, shrink it down to just 2 video frames
560            ahead of the window root (taking direction into account).
561         */
562
563         samplecnt_t const d = (quarter_frame_duration * 4 * sample_tolerance);
564
565         switch (parser.mtc_running()) {
566         case MTC_Forward:
567                 window_begin = root;
568                 transport_direction = 1;
569                 window_end = root + d;
570                 break;
571
572         case MTC_Backward:
573                 transport_direction = -1;
574                 if (root > d) {
575                         window_begin = root - d;
576                         window_end = root;
577                 } else {
578                         window_begin = 0;
579                 }
580                 window_end = root;
581                 break;
582
583         default:
584                 /* do nothing */
585                 break;
586         }
587
588         DEBUG_TRACE (DEBUG::MTC, string_compose ("reset MTC window @ %3, now %1 .. %2\n", window_begin, window_end, root));
589 }
590
591 /* main entry point from session_process.cc
592 xo * in process callback context */
593 bool
594 MTC_TransportMaster::speed_and_position (double& speed, samplepos_t& pos, samplepos_t now)
595 {
596         SafeTime last;
597
598         if (!_collect) {
599                 return false;
600         }
601
602         read_current (&last);
603
604         DEBUG_TRACE (DEBUG::MTC, string_compose ("speed&pos: timestamp %1 speed %2 dir %4 now %5 last-in %6\n",
605                                                  last.timestamp,
606                                                  last.speed,
607                                                  transport_direction,
608                                                  now,
609                                                  last_inbound_frame));
610
611         if (last.timestamp == 0) {
612                 return false;
613         }
614
615         if (last_inbound_frame && now > last_inbound_frame && now - last_inbound_frame > labs(seekahead_distance())) {
616                 /* no timecode for two cycles - conclude that it's stopped */
617
618                 if (!Config->get_transport_masters_just_roll_when_sync_lost()) {
619                         speed = 0;
620                         pos = last.position;
621                         _current_delta = 0;
622                         queue_reset (false);
623                         DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC not seen for 2 samples - reset pending, pos = %1\n", pos));
624                         return false;
625                 }
626         }
627
628
629         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));
630
631         speed = last.speed;
632
633         /* provide a .1% deadzone to lock the speed */
634         if (fabs (speed - 1.0) <= 0.001) {
635                 speed = 1.0;
636         }
637
638         pos =  last.position;
639         pos += (now - last.timestamp) * speed;
640
641         DEBUG_TRACE (DEBUG::MTC, string_compose ("MTCsync spd: %1 pos: %2 | last-pos: %3 | elapsed: %4\n",
642                                                  speed, pos, last.position, (now - last.timestamp)));
643
644         return true;
645 }
646
647 Timecode::TimecodeFormat
648 MTC_TransportMaster::apparent_timecode_format () const
649 {
650         return mtc_timecode;
651 }
652
653 std::string
654 MTC_TransportMaster::position_string() const
655 {
656         SafeTime last;
657         read_current (&last);
658         if (last.timestamp == 0 || reset_pending) {
659                 return " --:--:--:--";
660         }
661         return Timecode::timecode_format_sampletime(
662                 last.position,
663                 double(_session->sample_rate()),
664                 Timecode::timecode_to_frames_per_second(mtc_timecode),
665                 Timecode::timecode_has_drop_frames(mtc_timecode));
666 }
667
668 std::string
669 MTC_TransportMaster::delta_string () const
670 {
671         char delta[80];
672         SafeTime last;
673         read_current (&last);
674
675         delta[0] = '\0';
676
677         if (last.timestamp == 0 || reset_pending) {
678                 snprintf(delta, sizeof(delta), "\u2012\u2012\u2012\u2012");
679         } else {
680                 snprintf(delta, sizeof(delta), "\u0394<span foreground=\"green\" face=\"monospace\" >%s%s%" PRIi64 "</span>sm",
681                                 LEADINGZERO(abs(_current_delta)), PLUSMINUS(-_current_delta), abs(_current_delta));
682         }
683         return std::string(delta);
684 }