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