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