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