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