something for chris g. to try when he gets up before me
[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/enumwriter.h"
27 #include "pbd/failed_constructor.h"
28 #include "pbd/pthread_utils.h"
29
30 #include "midi++/port.h"
31 #include "ardour/debug.h"
32 #include "ardour/slave.h"
33 #include "ardour/session.h"
34 #include "ardour/audioengine.h"
35 #include "ardour/pi_controller.h"
36
37 #include "i18n.h"
38
39 using namespace std;
40 using namespace ARDOUR;
41 using namespace MIDI;
42 using namespace PBD;
43
44 /* length (in timecode frames) of the "window" that we consider legal given receipt of
45    a given timecode position. Ardour will try to chase within this window, and will
46    stop+locate+wait+chase if timecode arrives outside of it. The window extends entirely
47    in the current direction of motion, so if any timecode arrives that is before the most
48    recently received position (and without the direction of timecode reversing too), we
49    will stop+locate+wait+chase.
50 */
51
52 const int MTC_Slave::frame_tolerance = 2;
53
54 MTC_Slave::MTC_Slave (Session& s, MIDI::Port& p)
55         : session (s)
56 {
57         can_notify_on_unknown_rate = true;
58         did_reset_tc_format = false;
59         reset_pending = 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                 update_mtc_status (MIDI::MTC_Stopped);
194                 reset ();
195                 reset_window (mtc_frame);
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         DEBUG_TRACE (DEBUG::MTC, "queue reset of MTC slave state\n");
483         PBD::stacktrace (cerr, 35);
484         Glib::Mutex::Lock lm (reset_lock);
485         reset_pending++;
486 }
487
488 void
489 MTC_Slave::maybe_reset ()
490 {
491         reset_lock.lock ();
492
493         if (reset_pending) {
494                 DEBUG_TRACE (DEBUG::MTC, "actually reset\n");
495                 reset ();
496                 reset_pending = 0;
497         } 
498
499         reset_lock.unlock ();
500 }
501
502 void
503 MTC_Slave::reset ()
504 {
505         DEBUG_TRACE (DEBUG::MTC, "*****************\n\n\n MTC SLAVE reset ********************\n\n\n");
506
507         last_inbound_frame = 0;
508         current.guard1++;
509         current.position = 0;
510         current.timestamp = 0;
511         current.speed = 0;
512         current.guard2++;
513
514         window_begin = 0;
515         window_end = 0;
516         last_mtc_frame = 0;
517         last_mtc_timestamp = 0;
518
519         average_speed = 0;
520         have_first_speed_accumulator = false;
521         speed_accumulator_cnt = 0;
522
523         pic->reset();
524 }
525
526 void
527 MTC_Slave::reset_window (nframes64_t root)
528 {
529         
530         /* if we're waiting for the master to catch us after seeking ahead, keep the window
531            of acceptable MTC frames wide open. otherwise, shrink it down to just 2 video frames
532            ahead of the window root (taking direction into account).
533         */
534
535         DEBUG_TRACE (DEBUG::MTC, string_compose ("trying to reset MTC window with state = %1\n", enum_2_string (port->input()->mtc_running())));
536
537         switch (port->input()->mtc_running()) {
538         case MTC_Forward:
539                 DEBUG_TRACE (DEBUG::MTC, "set MTC window while running forward\n");
540                 window_begin = root;
541                 if (session.slave_state() == Session::Running) {
542                         window_end = root + (session.frames_per_timecode_frame() * frame_tolerance);
543                 } else {
544                         window_end = root + seekahead_distance ();
545                 }
546                 break;
547
548         case MTC_Backward:
549                 DEBUG_TRACE (DEBUG::MTC, "set MTC window while running backward\n");
550                 if (session.slave_state() == Session::Running) {
551                         nframes_t d = session.frames_per_timecode_frame() * frame_tolerance;
552                         if (root > d) {
553                                 window_begin = root - d;
554                                 window_end = root;
555                         } else {
556                                 window_begin = 0;
557                         }
558                 } else {
559                         nframes_t d = seekahead_distance ();
560                         if (root > d) {
561                                 window_begin = root - d;
562                         } else {
563                                 window_begin = 0;
564                         }
565                 }
566                 window_end = root;
567                 break;
568                 
569         default:
570                 DEBUG_TRACE (DEBUG::MTC, "not touching MTC window - MTC_Stopped\n");
571                 /* do nothing */
572                 break;
573         }
574
575         DEBUG_TRACE (DEBUG::MTC, string_compose ("legal MTC window now %1 .. %2\n", window_begin, window_end));
576 }
577
578 nframes64_t
579 MTC_Slave::seekahead_distance () const
580 {
581         /* 1 second */
582         return session.frame_rate();
583 }
584
585 bool
586 MTC_Slave::outside_window (nframes64_t pos) const
587 {
588         return ((pos < window_begin) || (pos > window_end));
589 }