more MTC debugging
[ardour.git] / libs / ardour / mtc_slave.cc
1 /*
2     Copyright (C) 2002-4 Paul Davis
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19 #include <iostream>
20 #include <errno.h>
21 #include <poll.h>
22 #include <sys/types.h>
23 #include <unistd.h>
24
25 #include "pbd/error.h"
26 #include "pbd/stacktrace.h"
27 #include "pbd/enumwriter.h"
28 #include "pbd/failed_constructor.h"
29 #include "pbd/pthread_utils.h"
30
31 #include "midi++/port.h"
32 #include "ardour/debug.h"
33 #include "ardour/slave.h"
34 #include "ardour/session.h"
35 #include "ardour/audioengine.h"
36 #include "ardour/pi_controller.h"
37
38 #include "i18n.h"
39
40 using namespace std;
41 using namespace ARDOUR;
42 using namespace MIDI;
43 using namespace PBD;
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
53 const int MTC_Slave::frame_tolerance = 2;
54
55 MTC_Slave::MTC_Slave (Session& s, MIDI::Port& p)
56         : session (s)
57 {
58         can_notify_on_unknown_rate = true;
59         did_reset_tc_format = false;
60
61         pic = new PIChaser();
62         
63         last_mtc_fps_byte = session.get_mtc_timecode_bits ();
64         mtc_frame = 0;
65
66         speed_accumulator_size = 16;
67         speed_accumulator = new double[speed_accumulator_size];
68
69         rebind (p);
70         reset ();
71 }
72
73 MTC_Slave::~MTC_Slave()
74 {
75         if (did_reset_tc_format) {
76                 session.config.set_timecode_format (saved_tc_format);
77         }
78
79         delete pic;
80         delete [] speed_accumulator;
81 }
82
83 bool 
84 MTC_Slave::give_slave_full_control_over_transport_speed() const
85 {
86         // return true; // for PiC control */
87         return false; // for Session-level computed varispeed
88 }
89
90 void
91 MTC_Slave::rebind (MIDI::Port& p)
92 {
93         port_connections.drop_connections ();
94         
95         port = &p;
96         
97         port->input()->mtc_time.connect_same_thread (port_connections,  boost::bind (&MTC_Slave::update_mtc_time, this, _1, _2, _3));
98         port->input()->mtc_qtr.connect_same_thread (port_connections, boost::bind (&MTC_Slave::update_mtc_qtr, this, _1, _2, _3));
99         port->input()->mtc_status.connect_same_thread (port_connections, boost::bind (&MTC_Slave::update_mtc_status, this, _1));
100 }
101
102 void
103 MTC_Slave::update_mtc_qtr (Parser& /*p*/, int which_qtr, nframes_t now)
104 {
105         DEBUG_TRACE (DEBUG::MTC, string_compose ("update MTC qtr does a reset, qtr = %1 now = %2\n", which_qtr, now));
106         maybe_reset ();
107
108         DEBUG_TRACE (DEBUG::MTC, string_compose ("qtr frame %1 at %2\n", which_qtr, now));
109         last_inbound_frame = now;
110 }
111
112 void
113 MTC_Slave::update_mtc_time (const byte *msg, bool was_full, nframes_t now)
114 {
115         /* "now" can be zero if this is called from a context where we do not have or do not want
116            to use a timestamp indicating when this MTC time was received. example: when we received
117            a locate command via MMC.
118         */
119
120         if (now) {
121                 DEBUG_TRACE (DEBUG::MTC, string_compose ("update MTC time does a reset, was full ? %1 now = %2\n", was_full, now));
122                 maybe_reset ();
123         }
124
125         Timecode::Time timecode;
126         TimecodeFormat tc_format;
127         bool reset_tc = true;
128         nframes64_t window_root = -1;
129
130         DEBUG_TRACE (DEBUG::MTC, string_compose ("full mtc time known at %1, full ? %2\n", now, was_full));
131         
132         timecode.hours = msg[3];
133         timecode.minutes = msg[2];
134         timecode.seconds = msg[1];
135         timecode.frames = msg[0];
136
137         last_mtc_fps_byte = msg[4];
138
139         switch (msg[4]) {
140         case MTC_24_FPS:
141                 timecode.rate = 24;
142                 timecode.drop = false;
143                 tc_format = timecode_24;
144                 can_notify_on_unknown_rate = true;
145                 break;
146         case MTC_25_FPS:
147                 timecode.rate = 25;
148                 timecode.drop = false;
149                 tc_format = timecode_25;
150                 can_notify_on_unknown_rate = true;
151                 break;
152         case MTC_30_FPS_DROP:
153                 timecode.rate = 30;
154                 timecode.drop = true;
155                 tc_format = timecode_30drop;
156                 can_notify_on_unknown_rate = true;
157                 break;
158         case MTC_30_FPS:
159                 timecode.rate = 30;
160                 timecode.drop = false;
161                 can_notify_on_unknown_rate = true;
162                 tc_format = timecode_30;
163                 break;
164         default:
165                 /* throttle error messages about unknown MTC rates */
166                 if (can_notify_on_unknown_rate) {
167                         error << string_compose (_("Unknown rate/drop value %1 in incoming MTC stream, session values used instead"),
168                                                  (int) msg[4])
169                               << endmsg;
170                         can_notify_on_unknown_rate = false;
171                 }
172                 timecode.rate = session.timecode_frames_per_second();
173                 timecode.drop = session.timecode_drop_frames();
174                 reset_tc = false;
175         }
176
177         if (reset_tc) {
178                 if (!did_reset_tc_format) {
179                         saved_tc_format = session.config.get_timecode_format();
180                         did_reset_tc_format = true;
181                 }
182                 session.config.set_timecode_format (tc_format);
183         }
184
185         DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC time timestamp = %1 TC %2 = frame %3 (from full message ? %4)\n", 
186                                                  now, timecode, mtc_frame, was_full));
187         
188         if (was_full || outside_window (mtc_frame)) {
189
190                 session.timecode_to_sample (timecode, mtc_frame, true, false);
191                 session.request_locate (mtc_frame, false);
192                 session.request_transport_speed (0);
193                 DEBUG_TRACE (DEBUG::MTC, string_compose ("reset MTC status to stopped, outside MTC window (%1 .. %2 vs. %3)\n",
194                                                          window_begin, window_end, mtc_frame));
195                 update_mtc_status (MIDI::MTC_Stopped);
196                 DEBUG_TRACE (DEBUG::MTC, string_compose ("outside, so window root reset to %1\n", mtc_frame));
197                 reset_window (mtc_frame);
198                 reset ();
199
200         } else {
201                         
202                 /* we've had the first set of 8 qtr frame messages, determine position
203                    and allow continuing qtr frame messages to provide position
204                    and speed information.
205                 */
206                 
207                 /* do a careful conversion of the timecode value to a position
208                    so that we take drop/nondrop and all that nonsense into 
209                    consideration.
210                 */
211
212                 session.timecode_to_sample (timecode, mtc_frame, true, false);
213                 
214                 /* We received the last quarter frame 7 quarter frames (1.75 mtc
215                    frames) after the instance when the contents of the mtc quarter
216                    frames were decided. Add time to compensate for the elapsed 1.75
217                    frames. Also compensate for audio latency.
218                 */
219                 
220                 mtc_frame += (long) (1.75 * session.frames_per_timecode_frame()) + session.worst_output_latency();
221
222
223                 if (now) {
224
225                         if (last_mtc_timestamp == 0) {
226
227                                 last_mtc_timestamp = now;
228                                 last_mtc_frame = mtc_frame;
229
230                         } else {
231
232                                 if (give_slave_full_control_over_transport_speed()) {
233                                         /* PIC 
234                                          * 
235                                          * its not the average, but we will assign it to current.speed below
236                                          */
237
238                                     static nframes64_t last_seen_timestamp = 0; 
239                                     static nframes64_t last_seen_position = 0; 
240
241                                     if ((now - last_seen_timestamp) < 300) {
242                                         mtc_frame = (mtc_frame + last_seen_position)/2;
243                                     }
244
245                                     last_seen_timestamp = now;
246                                     last_seen_position = mtc_frame;
247
248                                         
249                                         
250                                 } else {
251
252                                         /* Non-PiC 
253                                          */
254
255                                         nframes64_t time_delta = (now - last_mtc_timestamp);
256                                         
257                                         if (time_delta != 0) {
258                                                 double apparent_speed = (mtc_frame - last_mtc_frame) / (double) (time_delta);
259                                                 
260                                                 process_apparent_speed (apparent_speed);
261                                                 DEBUG_TRACE (DEBUG::Slave, string_compose ("apparent speed was %1 average is now %2\n", apparent_speed, average_speed));
262                                         } else {
263                                                 DEBUG_TRACE (DEBUG::Slave, string_compose ("no apparent calc, average is %1\n", average_speed));
264                                         }
265                                         
266                                         /* every second, recalibrate the starting point for the speed measurement */
267                                         if (mtc_frame - last_mtc_frame > session.frame_rate()) {
268                                                 last_mtc_timestamp = now;
269                                                 last_mtc_frame = mtc_frame;
270                                         }
271                                 }
272                         }
273
274                         current.guard1++;
275                         current.position = mtc_frame;
276                         current.timestamp = now;
277                         current.speed = average_speed;
278                         current.guard2++;
279                         window_root = mtc_frame;
280                 }
281         }
282
283         if (now) {
284                 last_inbound_frame = now;
285         }
286
287         if (window_root >= 0) {
288                 DEBUG_TRACE (DEBUG::MTC, string_compose ("window root reset to %1\n", window_root));
289                 reset_window (window_root);
290         }
291 }
292
293 void
294 MTC_Slave::process_apparent_speed (double this_speed)
295 {
296         DEBUG_TRACE (DEBUG::MTC, string_compose ("speed cnt %1 sz %2 have %3\n", speed_accumulator_cnt, speed_accumulator_size, have_first_speed_accumulator));
297
298         /* clamp to an expected range */
299
300         if (this_speed > 4.0 || this_speed < -4.0) {
301                 this_speed = average_speed;
302         }
303
304         if (speed_accumulator_cnt >= speed_accumulator_size) {
305                 have_first_speed_accumulator = true;
306                 speed_accumulator_cnt = 0;
307         }
308
309         speed_accumulator[speed_accumulator_cnt++] = this_speed;
310
311         if (have_first_speed_accumulator) {
312                 average_speed = 0.0;
313                 for (size_t i = 0; i < speed_accumulator_size; ++i) {
314                         average_speed += speed_accumulator[i];
315                 }
316                 average_speed /= speed_accumulator_size;
317         }
318 }
319
320 void
321 MTC_Slave::handle_locate (const MIDI::byte* mmc_tc)
322 {
323         MIDI::byte mtc[5];
324
325         mtc[4] = last_mtc_fps_byte;
326         mtc[3] = mmc_tc[0] & 0xf; /* hrs only */
327         mtc[2] = mmc_tc[1];
328         mtc[1] = mmc_tc[2];
329         mtc[0] = mmc_tc[3];
330
331         update_mtc_time (mtc, true, 0);
332 }
333
334 void
335 MTC_Slave::update_mtc_status (MIDI::MTC_Status status)
336 {
337         /* XXX !!! thread safety ... called from MIDI I/O context
338            and process() context (via ::speed_and_position())
339         */
340
341
342         DEBUG_TRACE (DEBUG::MTC, string_compose ("new MTC status %1\n", enum_2_string (status)));
343         switch (status) {
344         case MTC_Stopped:
345                 current.guard1++;
346                 current.position = mtc_frame;
347                 current.timestamp = 0;
348                 current.speed = 0;
349                 current.guard2++;
350
351                 break;
352
353         case MTC_Forward:
354                 current.guard1++;
355                 current.position = mtc_frame;
356                 current.timestamp = 0;
357                 current.speed = 0;
358                 current.guard2++;
359                 break;
360
361         case MTC_Backward:
362                 current.guard1++;
363                 current.position = mtc_frame;
364                 current.timestamp = 0;
365                 current.speed = 0;
366                 current.guard2++;
367                 break;
368         }
369         
370 }
371
372 void
373 MTC_Slave::read_current (SafeTime *st) const
374 {
375         int tries = 0;
376
377         do {
378                 if (tries == 10) {
379                         error << _("MTC Slave: atomic read of current time failed, sleeping!") << endmsg;
380                         usleep (20);
381                         tries = 0;
382                 }
383                 *st = current;
384                 tries++;
385
386         } while (st->guard1 != st->guard2);
387 }
388
389 bool
390 MTC_Slave::locked () const
391 {
392         return port->input()->mtc_locked();
393 }
394
395 bool
396 MTC_Slave::ok() const
397 {
398         return true;
399 }
400
401 bool
402 MTC_Slave::speed_and_position (double& speed, nframes64_t& pos)
403 {
404         nframes64_t now = session.engine().frame_time();
405         SafeTime last;
406         nframes_t elapsed;
407
408         read_current (&last);
409
410         if (last.timestamp == 0) {
411                 speed = 0;
412                 pos = last.position;
413                 DEBUG_TRACE (DEBUG::MTC, string_compose ("first call to MTC_Slave::speed_and_position, pos = %1\n", last.position));
414                 return true;
415         }
416
417         /* no timecode for 1/4 second ? conclude that its stopped */
418
419         if (last_inbound_frame && now > last_inbound_frame && now - last_inbound_frame > session.frame_rate() / 4) {
420                 speed = 0;
421                 pos = last.position;
422                 session.request_locate (pos, false);
423                 session.request_transport_speed (0);
424                 queue_reset ();
425                 DEBUG_TRACE (DEBUG::MTC, "MTC not seen for 1/4 second - reset pending\n");
426                 return false;
427         }
428
429         DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC::speed_and_position %1 %2\n", last.speed, last.position));
430
431         if (give_slave_full_control_over_transport_speed()) {
432             bool in_control = (session.slave_state() == Session::Running);
433             nframes64_t pic_want_locate = 0; 
434             //nframes64_t slave_pos = session.audible_frame();
435             nframes64_t slave_pos = session.transport_frame();
436             static double average_speed = 0;
437
438             average_speed = pic->get_ratio (last.timestamp, last.position, slave_pos, in_control );
439             pic_want_locate = pic->want_locate();
440
441             if (in_control && pic_want_locate) {
442                 last.speed = average_speed + (double) (pic_want_locate - session.transport_frame()) / (double)session.get_block_size();
443                 std::cout << "locate req " << pic_want_locate << " speed: " << average_speed << "\n"; 
444             } else {
445                 last.speed = average_speed;
446             }
447         }
448
449         if (last.speed == 0.0f) {
450
451                 elapsed = 0;
452
453         } else {
454
455                 /* scale elapsed time by the current MTC speed */
456
457                 if (last.timestamp && (now > last.timestamp)) {
458                         elapsed = (nframes_t) floor (last.speed * (now - last.timestamp));
459                         DEBUG_TRACE (DEBUG::MTC, string_compose ("last timecode received @ %1, now = %2, elapsed frames = %3 w/speed= %4\n",
460                                                                  last.timestamp, now, elapsed, last.speed));
461                 } else {
462                         elapsed = 0; /* XXX is this right? */
463                 }
464         }
465
466         /* now add the most recent timecode value plus the estimated elapsed interval */
467
468         pos = last.position + elapsed; 
469         speed = last.speed;
470
471         DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC::speed_and_position FINAL %1 %2\n", last.speed, pos));
472
473         return true;
474 }
475
476 ARDOUR::nframes_t
477 MTC_Slave::resolution() const
478 {
479         return (nframes_t) session.frames_per_timecode_frame();
480 }
481
482 void
483 MTC_Slave::queue_reset ()
484 {
485         DEBUG_TRACE (DEBUG::MTC, "queue reset of MTC slave state\n");
486         PBD::stacktrace (cerr, 35);
487         Glib::Mutex::Lock lm (reset_lock);
488         reset_pending++;
489 }
490
491 void
492 MTC_Slave::maybe_reset ()
493 {
494         reset_lock.lock ();
495
496         if (reset_pending) {
497                 DEBUG_TRACE (DEBUG::MTC, "actually reset\n");
498                 reset ();
499                 reset_pending = 0;
500         } 
501
502         reset_lock.unlock ();
503 }
504
505 void
506 MTC_Slave::reset ()
507 {
508         DEBUG_TRACE (DEBUG::MTC, "*****************\n\n\n MTC SLAVE reset ********************\n\n\n");
509         PBD::stacktrace (cerr, 35);
510         port->input()->reset_mtc_state ();
511
512         last_inbound_frame = 0;
513         current.guard1++;
514         current.position = 0;
515         current.timestamp = 0;
516         current.speed = 0;
517         current.guard2++;
518
519         window_begin = 0;
520         window_end = 0;
521         last_mtc_frame = 0;
522         last_mtc_timestamp = 0;
523
524         average_speed = 0;
525         have_first_speed_accumulator = false;
526         speed_accumulator_cnt = 0;
527
528         pic->reset();
529 }
530
531 void
532 MTC_Slave::reset_window (nframes64_t root)
533 {
534         
535         /* if we're waiting for the master to catch us after seeking ahead, keep the window
536            of acceptable MTC frames wide open. otherwise, shrink it down to just 2 video frames
537            ahead of the window root (taking direction into account).
538         */
539
540         DEBUG_TRACE (DEBUG::MTC, string_compose ("trying to reset MTC window with state = %1\n", enum_2_string (port->input()->mtc_running())));
541
542         switch (port->input()->mtc_running()) {
543         case MTC_Forward:
544                 DEBUG_TRACE (DEBUG::MTC, "set MTC window while running forward\n");
545                 window_begin = root;
546                 if (session.slave_state() == Session::Running) {
547                         window_end = root + (session.frames_per_timecode_frame() * frame_tolerance);
548                 } else {
549                         window_end = root + seekahead_distance ();
550                 }
551                 break;
552
553         case MTC_Backward:
554                 DEBUG_TRACE (DEBUG::MTC, "set MTC window while running backward\n");
555                 if (session.slave_state() == Session::Running) {
556                         nframes_t d = session.frames_per_timecode_frame() * frame_tolerance;
557                         if (root > d) {
558                                 window_begin = root - d;
559                                 window_end = root;
560                         } else {
561                                 window_begin = 0;
562                         }
563                 } else {
564                         nframes_t d = seekahead_distance ();
565                         if (root > d) {
566                                 window_begin = root - d;
567                         } else {
568                                 window_begin = 0;
569                         }
570                 }
571                 window_end = root;
572                 break;
573                 
574         default:
575                 DEBUG_TRACE (DEBUG::MTC, "not touching MTC window - MTC_Stopped\n");
576                 /* do nothing */
577                 break;
578         }
579
580         DEBUG_TRACE (DEBUG::MTC, string_compose ("legal MTC window now %1 .. %2\n", window_begin, window_end));
581 }
582
583 nframes64_t
584 MTC_Slave::seekahead_distance () const
585 {
586         /* 1 second */
587         return session.frame_rate();
588 }
589
590 bool
591 MTC_Slave::outside_window (nframes64_t pos) const
592 {
593         return ((pos < window_begin) || (pos > window_end));
594 }