c081de23b5ed07e785a6294d6511167be9edbeb8
[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 "pbd/i18n.h"
36
37 using namespace std;
38 using namespace ARDOUR;
39 using namespace MIDI;
40 using namespace PBD;
41 using namespace Timecode;
42
43 /* length (in timecode frames) of the "window" that we consider legal given receipt of
44    a given timecode position. Ardour will try to chase within this window, and will
45    stop+locate+wait+chase if timecode arrives outside of it. The window extends entirely
46    in the current direction of motion, so if any timecode arrives that is before the most
47    recently received position (and without the direction of timecode reversing too), we
48    will stop+locate+wait+chase.
49 */
50 const int MTC_TransportMaster::sample_tolerance = 2;
51
52 MTC_TransportMaster::MTC_TransportMaster (std::string const & name)
53         : TimecodeTransportMaster (name, MTC)
54         , can_notify_on_unknown_rate (true)
55         , mtc_frame (0)
56         , mtc_frame_dll (0)
57         , last_inbound_frame (0)
58         , window_begin (0)
59         , window_end (0)
60         , first_mtc_timestamp (0)
61         , did_reset_tc_format (false)
62         , reset_pending (0)
63         , reset_position (false)
64         , transport_direction (1)
65         , busy_guard1 (0)
66         , busy_guard2 (0)
67         , printed_timecode_warning (false)
68 {
69         if ((_port = create_midi_port (string_compose ("%1 in", name))) == 0) {
70                 throw failed_constructor();
71         }
72
73         DEBUG_TRACE (DEBUG::Slave, string_compose ("MTC registered %1\n", _port->name()));
74
75         init ();
76 }
77
78 MTC_TransportMaster::~MTC_TransportMaster()
79 {
80         port_connections.drop_connections();
81         config_connection.disconnect();
82
83         while (busy_guard1 != busy_guard2) {
84                 /* make sure MIDI parser is not currently calling any callbacks in here,
85                  * else there's a segfault ahead!
86                  *
87                  * XXX this is called from jack rt-context :(
88                  * TODO fix libs/ardour/session_transport.cc:1321 (delete _slave;)
89                  */
90                 sched_yield();
91         }
92
93         if (did_reset_tc_format) {
94                 _session->config.set_timecode_format (saved_tc_format);
95         }
96 }
97
98 void
99 MTC_TransportMaster::init ()
100 {
101         reset (true);
102 }
103
104 void
105 MTC_TransportMaster::set_session (Session *s)
106 {
107         config_connection.disconnect ();
108         port_connections.drop_connections();
109
110         _session = s;
111
112         if (_session) {
113
114                 last_mtc_fps_byte = _session->get_mtc_timecode_bits ();
115                 quarter_frame_duration = (double) (_session->samples_per_timecode_frame() / 4.0);
116                 mtc_timecode = _session->config.get_timecode_format();
117                 a3e_timecode = _session->config.get_timecode_format();
118
119                 parse_timecode_offset ();
120                 reset (true);
121
122                 parser.mtc_time.connect_same_thread (port_connections,  boost::bind (&MTC_TransportMaster::update_mtc_time, this, _1, _2, _3));
123                 parser.mtc_qtr.connect_same_thread (port_connections, boost::bind (&MTC_TransportMaster::update_mtc_qtr, this, _1, _2, _3));
124                 parser.mtc_status.connect_same_thread (port_connections, boost::bind (&MTC_TransportMaster::update_mtc_status, this, _1));
125
126                 _session->config.ParameterChanged.connect_same_thread (config_connection, boost::bind (&MTC_TransportMaster::parameter_changed, this, _1));
127         }
128 }
129
130 void
131 MTC_TransportMaster::pre_process (MIDI::pframes_t nframes, samplepos_t now, boost::optional<samplepos_t> session_pos)
132 {
133         /* Read and parse incoming MIDI */
134
135         maybe_reset ();
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                 current.update (0, 0, 0);
228         } else {
229                 current.update (current.position, 0, 0);
230         }
231         first_mtc_timestamp = 0;
232         window_begin = 0;
233         window_end = 0;
234         transport_direction = 1;
235         _current_delta = 0;
236 }
237
238 void
239 MTC_TransportMaster::handle_locate (const MIDI::byte* mmc_tc)
240 {
241         MIDI::byte mtc[5];
242         DEBUG_TRACE (DEBUG::MTC, "MTC_TransportMaster::handle_locate\n");
243
244         mtc[4] = last_mtc_fps_byte;
245         mtc[3] = mmc_tc[0] & 0xf; /* hrs only */
246         mtc[2] = mmc_tc[1];
247         mtc[1] = mmc_tc[2];
248         mtc[0] = mmc_tc[3];
249
250         update_mtc_time (mtc, true, 0);
251 }
252
253 void
254 MTC_TransportMaster::init_mtc_dll(samplepos_t tme, double qtr)
255 {
256         const double omega = 2.0 * M_PI * qtr / 2.0 / double(_session->sample_rate());
257         b = 1.4142135623730950488 * omega;
258         c = omega * omega;
259
260         e2 = qtr;
261         t0 = double(tme);
262         t1 = t0 + e2;
263         DEBUG_TRACE (DEBUG::MTC, string_compose ("[re-]init MTC DLL %1 %2 %3\n", t0, t1, e2));
264 }
265
266 /* called from MIDI parser */
267 void
268 MTC_TransportMaster::update_mtc_qtr (Parser& p, int which_qtr, samplepos_t now)
269 {
270         busy_guard1++;
271         const double qtr_d = quarter_frame_duration;
272
273         mtc_frame_dll += qtr_d * (double) transport_direction;
274         mtc_frame = rint(mtc_frame_dll);
275
276         DEBUG_TRACE (DEBUG::MTC, string_compose ("qtr sample %1 at %2 -> mtc_frame: %3\n", which_qtr, now, mtc_frame));
277
278         double mtc_speed = 0;
279         if (first_mtc_timestamp != 0) {
280                 /* update MTC DLL and calculate speed */
281                 const double e = mtc_frame_dll - (double)transport_direction * ((double)now - (double)current.timestamp + t0);
282                 t0 = t1;
283                 t1 += b * e + e2;
284                 e2 += c * e;
285
286                 mtc_speed = (t1 - t0) / qtr_d;
287                 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));
288
289                 current.update (mtc_frame, now, mtc_speed);
290         }
291
292         maybe_reset ();
293
294         busy_guard2++;
295 }
296
297 /* called from MIDI parser _after_ update_mtc_qtr()
298  * when a full TC has been received
299  * OR on locate */
300 void
301 MTC_TransportMaster::update_mtc_time (const MIDI::byte *msg, bool was_full, samplepos_t now)
302 {
303         busy_guard1++;
304
305         /* "now" can be zero if this is called from a context where we do not have or do not want
306            to use a timestamp indicating when this MTC time was received. example: when we received
307            a locate command via MMC.
308         */
309         DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC::update_mtc_time - TID:%1\n", pthread_name()));
310         TimecodeFormat tc_format;
311         bool reset_tc = true;
312
313         timecode.hours = msg[3];
314         timecode.minutes = msg[2];
315         timecode.seconds = msg[1];
316         timecode.frames = msg[0];
317
318         last_mtc_fps_byte = msg[4];
319
320         DEBUG_TRACE (DEBUG::MTC, string_compose ("full mtc time known at %1, full ? %2\n", now, was_full));
321
322         if (now) {
323                 maybe_reset ();
324         }
325
326         switch (msg[4]) {
327         case MTC_24_FPS:
328                 timecode.rate = 24;
329                 timecode.drop = false;
330                 tc_format = timecode_24;
331                 can_notify_on_unknown_rate = true;
332                 break;
333         case MTC_25_FPS:
334                 timecode.rate = 25;
335                 timecode.drop = false;
336                 tc_format = timecode_25;
337                 can_notify_on_unknown_rate = true;
338                 break;
339         case MTC_30_FPS_DROP:
340                 if (fr2997()) {
341                         tc_format = Timecode::timecode_2997000drop;
342                         timecode.rate = (29970.0/1000.0);
343                 } else {
344                         tc_format = timecode_2997drop;
345                         timecode.rate = (30000.0/1001.0);
346                 }
347                 timecode.drop = true;
348                 can_notify_on_unknown_rate = true;
349                 break;
350         case MTC_30_FPS:
351                 timecode.rate = 30;
352                 timecode.drop = false;
353                 can_notify_on_unknown_rate = true;
354                 tc_format = timecode_30;
355                 break;
356         default:
357                 /* throttle error messages about unknown MTC rates */
358                 if (can_notify_on_unknown_rate) {
359                         error << string_compose (_("Unknown rate/drop value %1 in incoming MTC stream, session values used instead"),
360                                                  (int) msg[4])
361                               << endmsg;
362                         can_notify_on_unknown_rate = false;
363                 }
364                 timecode.rate = _session->timecode_frames_per_second();
365                 timecode.drop = _session->timecode_drop_frames();
366                 reset_tc = false;
367         }
368
369         if (reset_tc) {
370                 TimecodeFormat cur_timecode = _session->config.get_timecode_format();
371                 if (Config->get_timecode_sync_frame_rate()) {
372                         /* enforce time-code */
373                         if (!did_reset_tc_format) {
374                                 saved_tc_format = cur_timecode;
375                                 did_reset_tc_format = true;
376                         }
377                         if (cur_timecode != tc_format) {
378                                 if (ceil(Timecode::timecode_to_frames_per_second(cur_timecode)) != ceil(Timecode::timecode_to_frames_per_second(tc_format))) {
379                                         warning << string_compose(_("Session framerate adjusted from %1 TO: MTC's %2."),
380                                                         Timecode::timecode_format_name(cur_timecode),
381                                                         Timecode::timecode_format_name(tc_format))
382                                                 << endmsg;
383                                 }
384                         }
385                         _session->config.set_timecode_format (tc_format);
386                 } else {
387                         /* only warn about TC mismatch */
388                         if (mtc_timecode != tc_format) printed_timecode_warning = false;
389                         if (a3e_timecode != cur_timecode) printed_timecode_warning = false;
390
391                         if (cur_timecode != tc_format && ! printed_timecode_warning) {
392                                 if (ceil(Timecode::timecode_to_frames_per_second(cur_timecode)) != ceil(Timecode::timecode_to_frames_per_second(tc_format))) {
393                                         warning << string_compose(_("Session and MTC framerate mismatch: MTC:%1 %2:%3."),
394                                                                   Timecode::timecode_format_name(tc_format),
395                                                                   PROGRAM_NAME,
396                                                                   Timecode::timecode_format_name(cur_timecode))
397                                                 << endmsg;
398                                 }
399                                 printed_timecode_warning = true;
400                         }
401                 }
402                 mtc_timecode = tc_format;
403                 a3e_timecode = cur_timecode;
404
405                 speedup_due_to_tc_mismatch = timecode.rate / Timecode::timecode_to_frames_per_second(a3e_timecode);
406         }
407
408         /* do a careful conversion of the timecode value to a position
409            so that we take drop/nondrop and all that nonsense into
410            consideration.
411         */
412
413         quarter_frame_duration = (double(_session->sample_rate()) / (double) timecode.rate / 4.0);
414
415         Timecode::timecode_to_sample (timecode, mtc_frame, true, false,
416                 double(_session->sample_rate()),
417                 _session->config.get_subframes_per_frame(),
418                 timecode_negative_offset, timecode_offset
419                 );
420
421         DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC at %1 TC %2 = mtc_frame %3 (from full message ? %4) tc-ratio %5\n",
422                                                  now, timecode, mtc_frame, was_full, speedup_due_to_tc_mismatch));
423
424         if (was_full || outside_window (mtc_frame)) {
425                 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));
426                 _session->set_requested_return_sample (-1);
427                 _session->request_transport_speed (0, TRS_MTC);
428                 _session->request_locate (mtc_frame, false, TRS_MTC);
429                 update_mtc_status (MIDI::MTC_Stopped);
430                 reset (false);
431                 reset_window (mtc_frame);
432         } else {
433
434                 /* we've had the first set of 8 qtr sample messages, determine position
435                    and allow continuing qtr sample messages to provide position
436                    and speed information.
437                 */
438
439                 /* We received the last quarter frame 7 quarter frames (1.75 mtc
440                    samples) after the instance when the contents of the mtc quarter
441                    samples were decided. Add time to compensate for the elapsed 1.75
442                    samples.
443                 */
444                 double qtr = quarter_frame_duration;
445                 long int mtc_off = (long) rint(7.0 * qtr);
446
447                 DEBUG_TRACE (DEBUG::MTC, string_compose ("new mtc_frame: %1 | MTC-FpT: %2 A3-FpT:%3\n",
448                                                          mtc_frame, (4.0*qtr), _session->samples_per_timecode_frame()));
449
450                 switch (parser.mtc_running()) {
451                 case MTC_Backward:
452                         mtc_frame -= mtc_off;
453                         qtr *= -1.0;
454                         break;
455                 case MTC_Forward:
456                         mtc_frame += mtc_off;
457                         break;
458                 default:
459                         break;
460                 }
461
462                 DEBUG_TRACE (DEBUG::MTC, string_compose ("new mtc_frame (w/offset) = %1\n", mtc_frame));
463
464                 if (now) {
465                         if (first_mtc_timestamp == 0 || current.timestamp == 0) {
466                                 first_mtc_timestamp = now;
467                                 init_mtc_dll(mtc_frame, qtr);
468                                 mtc_frame_dll = mtc_frame;
469                         }
470                         current.update (mtc_frame, now, current.speed);
471                         reset_window (mtc_frame);
472                 }
473         }
474
475         busy_guard2++;
476 }
477
478 void
479 MTC_TransportMaster::update_mtc_status (MIDI::MTC_Status status)
480 {
481         /* XXX !!! thread safety ... called from MIDI I/O context
482          * on locate (via ::update_mtc_time())
483          */
484         DEBUG_TRACE (DEBUG::MTC, string_compose("MTC_TransportMaster::update_mtc_status - TID:%1 MTC:%2\n", pthread_name(), mtc_frame));
485         return; // why was this fn needed anyway ? it just messes up things -> use reset.
486         busy_guard1++;
487
488         switch (status) {
489         case MTC_Stopped:
490                 current.update (mtc_frame, 0, 0);
491                 break;
492
493         case MTC_Forward:
494                 current.update (mtc_frame, 0, 0);
495                 break;
496
497         case MTC_Backward:
498                 current.update (mtc_frame, 0, 0);
499                 break;
500         }
501         busy_guard2++;
502 }
503
504 void
505 MTC_TransportMaster::reset_window (samplepos_t root)
506 {
507         /* if we're waiting for the master to catch us after seeking ahead, keep the window
508            of acceptable MTC samples wide open. otherwise, shrink it down to just 2 video frames
509            ahead of the window root (taking direction into account).
510         */
511
512         samplecnt_t const d = (quarter_frame_duration * 4 * sample_tolerance);
513
514         switch (parser.mtc_running()) {
515         case MTC_Forward:
516                 window_begin = root;
517                 transport_direction = 1;
518                 window_end = root + d;
519                 break;
520
521         case MTC_Backward:
522                 transport_direction = -1;
523                 if (root > d) {
524                         window_begin = root - d;
525                         window_end = root;
526                 } else {
527                         window_begin = 0;
528                 }
529                 window_end = root;
530                 break;
531
532         default:
533                 /* do nothing */
534                 break;
535         }
536
537         DEBUG_TRACE (DEBUG::MTC, string_compose ("reset MTC window @ %3, now %1 .. %2\n", window_begin, window_end, root));
538 }
539
540 Timecode::TimecodeFormat
541 MTC_TransportMaster::apparent_timecode_format () const
542 {
543         return mtc_timecode;
544 }
545
546 std::string
547 MTC_TransportMaster::position_string() const
548 {
549         SafeTime last;
550         current.safe_read (last);
551         if (last.timestamp == 0 || reset_pending) {
552                 return " --:--:--:--";
553         }
554         return Timecode::timecode_format_sampletime(
555                 last.position,
556                 double(_session->sample_rate()),
557                 Timecode::timecode_to_frames_per_second(mtc_timecode),
558                 Timecode::timecode_has_drop_frames(mtc_timecode));
559 }
560
561 std::string
562 MTC_TransportMaster::delta_string () const
563 {
564         char delta[80];
565         SafeTime last;
566         current.safe_read (last);
567
568         delta[0] = '\0';
569
570         if (last.timestamp == 0 || reset_pending) {
571                 snprintf(delta, sizeof(delta), "\u2012\u2012\u2012\u2012");
572         } else {
573                 snprintf(delta, sizeof(delta), "\u0394<span foreground=\"green\" face=\"monospace\" >%s%s%" PRIi64 "</span>sm",
574                                 LEADINGZERO(abs(_current_delta)), PLUSMINUS(-_current_delta), abs(_current_delta));
575         }
576         return std::string(delta);
577 }