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