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)",
190                                                          window_begin, window_end, mtc_frame));
191                 update_mtc_status (MIDI::MTC_Stopped);
192                 reset_window (mtc_frame);
193                 reset ();
194
195         } else {
196                         
197                 /* we've had the first set of 8 qtr frame messages, determine position
198                    and allow continuing qtr frame messages to provide position
199                    and speed information.
200                 */
201                 
202                 /* do a careful conversion of the timecode value to a position
203                    so that we take drop/nondrop and all that nonsense into 
204                    consideration.
205                 */
206
207                 session.timecode_to_sample (timecode, mtc_frame, true, false);
208                 
209                 /* We received the last quarter frame 7 quarter frames (1.75 mtc
210                    frames) after the instance when the contents of the mtc quarter
211                    frames were decided. Add time to compensate for the elapsed 1.75
212                    frames. Also compensate for audio latency.
213                 */
214                 
215                 mtc_frame += (long) (1.75 * session.frames_per_timecode_frame()) + session.worst_output_latency();
216
217
218                 if (now) {
219
220                         if (last_mtc_timestamp == 0) {
221
222                                 last_mtc_timestamp = now;
223                                 last_mtc_frame = mtc_frame;
224
225                         } else {
226
227                                 if (give_slave_full_control_over_transport_speed()) {
228                                         /* PIC 
229                                          * 
230                                          * its not the average, but we will assign it to current.speed below
231                                          */
232
233                                     static nframes64_t last_seen_timestamp = 0; 
234                                     static nframes64_t last_seen_position = 0; 
235
236                                     if ((now - last_seen_timestamp) < 300) {
237                                         mtc_frame = (mtc_frame + last_seen_position)/2;
238                                     }
239
240                                     last_seen_timestamp = now;
241                                     last_seen_position = mtc_frame;
242
243                                         
244                                         
245                                 } else {
246
247                                         /* Non-PiC 
248                                          */
249
250                                         nframes64_t time_delta = (now - last_mtc_timestamp);
251                                         
252                                         if (time_delta != 0) {
253                                                 double apparent_speed = (mtc_frame - last_mtc_frame) / (double) (time_delta);
254                                                 
255                                                 process_apparent_speed (apparent_speed);
256                                                 DEBUG_TRACE (DEBUG::Slave, string_compose ("apparent speed was %1 average is now %2\n", apparent_speed, average_speed));
257                                         } else {
258                                                 DEBUG_TRACE (DEBUG::Slave, string_compose ("no apparent calc, average is %1\n", average_speed));
259                                         }
260                                         
261                                         /* every second, recalibrate the starting point for the speed measurement */
262                                         if (mtc_frame - last_mtc_frame > session.frame_rate()) {
263                                                 last_mtc_timestamp = now;
264                                                 last_mtc_frame = mtc_frame;
265                                         }
266                                 }
267                         }
268
269                         current.guard1++;
270                         current.position = mtc_frame;
271                         current.timestamp = now;
272                         current.speed = average_speed;
273                         current.guard2++;
274                         window_root = mtc_frame;
275                 }
276         }
277
278         if (now) {
279                 last_inbound_frame = now;
280         }
281
282         if (window_root >= 0) {
283                 reset_window (window_root);
284         }
285 }
286
287 void
288 MTC_Slave::process_apparent_speed (double this_speed)
289 {
290         DEBUG_TRACE (DEBUG::MTC, string_compose ("speed cnt %1 sz %2 have %3\n", speed_accumulator_cnt, speed_accumulator_size, have_first_speed_accumulator));
291
292         /* clamp to an expected range */
293
294         if (this_speed > 4.0 || this_speed < -4.0) {
295                 this_speed = average_speed;
296         }
297
298         if (speed_accumulator_cnt >= speed_accumulator_size) {
299                 have_first_speed_accumulator = true;
300                 speed_accumulator_cnt = 0;
301         }
302
303         speed_accumulator[speed_accumulator_cnt++] = this_speed;
304
305         if (have_first_speed_accumulator) {
306                 average_speed = 0.0;
307                 for (size_t i = 0; i < speed_accumulator_size; ++i) {
308                         average_speed += speed_accumulator[i];
309                 }
310                 average_speed /= speed_accumulator_size;
311         }
312 }
313
314 void
315 MTC_Slave::handle_locate (const MIDI::byte* mmc_tc)
316 {
317         MIDI::byte mtc[5];
318
319         mtc[4] = last_mtc_fps_byte;
320         mtc[3] = mmc_tc[0] & 0xf; /* hrs only */
321         mtc[2] = mmc_tc[1];
322         mtc[1] = mmc_tc[2];
323         mtc[0] = mmc_tc[3];
324
325         update_mtc_time (mtc, true, 0);
326 }
327
328 void
329 MTC_Slave::update_mtc_status (MIDI::MTC_Status status)
330 {
331         /* XXX !!! thread safety ... called from MIDI I/O context
332            and process() context (via ::speed_and_position())
333         */
334
335
336         DEBUG_TRACE (DEBUG::MTC, string_compose ("new MTC status %1\n", enum_2_string (status)));
337         switch (status) {
338         case MTC_Stopped:
339                 current.guard1++;
340                 current.position = mtc_frame;
341                 current.timestamp = 0;
342                 current.speed = 0;
343                 current.guard2++;
344
345                 break;
346
347         case MTC_Forward:
348                 current.guard1++;
349                 current.position = mtc_frame;
350                 current.timestamp = 0;
351                 current.speed = 0;
352                 current.guard2++;
353                 break;
354
355         case MTC_Backward:
356                 current.guard1++;
357                 current.position = mtc_frame;
358                 current.timestamp = 0;
359                 current.speed = 0;
360                 current.guard2++;
361                 break;
362         }
363         
364 }
365
366 void
367 MTC_Slave::read_current (SafeTime *st) const
368 {
369         int tries = 0;
370
371         do {
372                 if (tries == 10) {
373                         error << _("MTC Slave: atomic read of current time failed, sleeping!") << endmsg;
374                         usleep (20);
375                         tries = 0;
376                 }
377                 *st = current;
378                 tries++;
379
380         } while (st->guard1 != st->guard2);
381 }
382
383 bool
384 MTC_Slave::locked () const
385 {
386         return port->input()->mtc_locked();
387 }
388
389 bool
390 MTC_Slave::ok() const
391 {
392         return true;
393 }
394
395 bool
396 MTC_Slave::speed_and_position (double& speed, nframes64_t& pos)
397 {
398         nframes64_t now = session.engine().frame_time();
399         SafeTime last;
400         nframes_t elapsed;
401
402         read_current (&last);
403
404         if (last.timestamp == 0) {
405                 speed = 0;
406                 pos = last.position;
407                 DEBUG_TRACE (DEBUG::MTC, string_compose ("first call to MTC_Slave::speed_and_position, pos = %1\n", last.position));
408                 return true;
409         }
410
411         /* no timecode for 1/4 second ? conclude that its stopped */
412
413         if (last_inbound_frame && now > last_inbound_frame && now - last_inbound_frame > session.frame_rate() / 4) {
414                 speed = 0;
415                 pos = last.position;
416                 session.request_locate (pos, false);
417                 session.request_transport_speed (0);
418                 queue_reset ();
419                 DEBUG_TRACE (DEBUG::MTC, "MTC not seen for 1/4 second - reset pending\n");
420                 return false;
421         }
422
423         DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC::speed_and_position %1 %2\n", last.speed, last.position));
424
425         if (give_slave_full_control_over_transport_speed()) {
426             bool in_control = (session.slave_state() == Session::Running);
427             nframes64_t pic_want_locate = 0; 
428             //nframes64_t slave_pos = session.audible_frame();
429             nframes64_t slave_pos = session.transport_frame();
430             static double average_speed = 0;
431
432             average_speed = pic->get_ratio (last.timestamp, last.position, slave_pos, in_control );
433             pic_want_locate = pic->want_locate();
434
435             if (in_control && pic_want_locate) {
436                 last.speed = average_speed + (double) (pic_want_locate - session.transport_frame()) / (double)session.get_block_size();
437                 std::cout << "locate req " << pic_want_locate << " speed: " << average_speed << "\n"; 
438             } else {
439                 last.speed = average_speed;
440             }
441         }
442
443         if (last.speed == 0.0f) {
444
445                 elapsed = 0;
446
447         } else {
448
449                 /* scale elapsed time by the current MTC speed */
450
451                 if (last.timestamp && (now > last.timestamp)) {
452                         elapsed = (nframes_t) floor (last.speed * (now - last.timestamp));
453                         DEBUG_TRACE (DEBUG::MTC, string_compose ("last timecode received @ %1, now = %2, elapsed frames = %3 w/speed= %4\n",
454                                                                  last.timestamp, now, elapsed, last.speed));
455                 } else {
456                         elapsed = 0; /* XXX is this right? */
457                 }
458         }
459
460         /* now add the most recent timecode value plus the estimated elapsed interval */
461
462         pos = last.position + elapsed; 
463         speed = last.speed;
464
465         DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC::speed_and_position FINAL %1 %2\n", last.speed, pos));
466
467         return true;
468 }
469
470 ARDOUR::nframes_t
471 MTC_Slave::resolution() const
472 {
473         return (nframes_t) session.frames_per_timecode_frame();
474 }
475
476 void
477 MTC_Slave::queue_reset ()
478 {
479         Glib::Mutex::Lock lm (reset_lock);
480         reset_pending++;
481 }
482
483 void
484 MTC_Slave::maybe_reset ()
485 {
486         reset_lock.lock ();
487
488         if (reset_pending) {
489                 reset ();
490                 reset_pending = 0;
491         } 
492
493         reset_lock.unlock ();
494 }
495
496 void
497 MTC_Slave::reset ()
498 {
499         port->input()->reset_mtc_state ();
500
501         last_inbound_frame = 0;
502         current.guard1++;
503         current.position = 0;
504         current.timestamp = 0;
505         current.speed = 0;
506         current.guard2++;
507
508         window_begin = 0;
509         window_end = 0;
510         last_mtc_frame = 0;
511         last_mtc_timestamp = 0;
512
513         average_speed = 0;
514         have_first_speed_accumulator = false;
515         speed_accumulator_cnt = 0;
516
517         pic->reset();
518 }
519
520 void
521 MTC_Slave::reset_window (nframes64_t root)
522 {
523         
524         /* if we're waiting for the master to catch us after seeking ahead, keep the window
525            of acceptable MTC frames wide open. otherwise, shrink it down to just 2 video frames
526            ahead of the window root (taking direction into account).
527         */
528
529         switch (port->input()->mtc_running()) {
530         case MTC_Forward:
531                 window_begin = root;
532                 if (session.slave_state() == Session::Running) {
533                         window_end = root + (session.frames_per_timecode_frame() * frame_tolerance);
534                 } else {
535                         window_end = root + seekahead_distance ();
536                 }
537                 DEBUG_TRACE (DEBUG::MTC, string_compose ("legal MTC window now %1 .. %2\n", window_begin, window_end));
538                 break;
539
540         case MTC_Backward:
541                 if (session.slave_state() == Session::Running) {
542                         nframes_t d = session.frames_per_timecode_frame() * frame_tolerance;
543                         if (root > d) {
544                                 window_begin = root - d;
545                                 window_end = root;
546                         } else {
547                                 window_begin = 0;
548                         }
549                 } else {
550                         nframes_t d = seekahead_distance ();
551                         if (root > d) {
552                                 window_begin = root - d;
553                         } else {
554                                 window_begin = 0;
555                         }
556                 }
557                 window_end = root;
558                 DEBUG_TRACE (DEBUG::MTC, string_compose ("legal MTC window now %1 .. %2\n", window_begin, window_end));
559                 break;
560                 
561         default:
562                 /* do nothing */
563                 break;
564         }
565 }
566
567 nframes64_t
568 MTC_Slave::seekahead_distance () const
569 {
570         /* 1 second */
571         return session.frame_rate();
572 }
573
574 bool
575 MTC_Slave::outside_window (nframes64_t pos) const
576 {
577         return ((pos < window_begin) || (pos > window_end));
578 }