remove using namespace sigc everywhere to ensure clarity over which bind/mem_fun...
[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         delete pic;
77         delete [] speed_accumulator;
78 }
79
80 bool 
81 MTC_Slave::give_slave_full_control_over_transport_speed() const
82 {
83         // return true; // for PiC control */
84         return false; // for Session-level computed varispeed
85 }
86
87 void
88 MTC_Slave::rebind (MIDI::Port& p)
89 {
90         for (vector<sigc::connection>::iterator i = connections.begin(); i != connections.end(); ++i) {
91                 (*i).disconnect ();
92         }
93
94         port = &p;
95
96         connections.push_back (port->input()->mtc_time.connect (sigc::mem_fun (*this, &MTC_Slave::update_mtc_time)));
97         connections.push_back (port->input()->mtc_qtr.connect (sigc::mem_fun (*this, &MTC_Slave::update_mtc_qtr)));
98         connections.push_back (port->input()->mtc_status.connect (sigc::mem_fun (*this, &MTC_Slave::update_mtc_status)));
99 }
100
101 void
102 MTC_Slave::update_mtc_qtr (Parser& /*p*/, int which_qtr, nframes_t now)
103 {
104         maybe_reset ();
105
106         DEBUG_TRACE (DEBUG::MTC, string_compose ("qtr frame %1 at %2\n", which_qtr, now));
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_window (mtc_frame);
192                 reset ();
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
335         DEBUG_TRACE (DEBUG::MTC, string_compose ("new MTC status %1\n", enum_2_string (status)));
336         switch (status) {
337         case MTC_Stopped:
338                 current.guard1++;
339                 current.position = mtc_frame;
340                 current.timestamp = 0;
341                 current.speed = 0;
342                 current.guard2++;
343
344                 break;
345
346         case MTC_Forward:
347                 current.guard1++;
348                 current.position = mtc_frame;
349                 current.timestamp = 0;
350                 current.speed = 0;
351                 current.guard2++;
352                 break;
353
354         case MTC_Backward:
355                 current.guard1++;
356                 current.position = mtc_frame;
357                 current.timestamp = 0;
358                 current.speed = 0;
359                 current.guard2++;
360                 break;
361         }
362         
363 }
364
365 void
366 MTC_Slave::read_current (SafeTime *st) const
367 {
368         int tries = 0;
369
370         do {
371                 if (tries == 10) {
372                         error << _("MTC Slave: atomic read of current time failed, sleeping!") << endmsg;
373                         usleep (20);
374                         tries = 0;
375                 }
376                 *st = current;
377                 tries++;
378
379         } while (st->guard1 != st->guard2);
380 }
381
382 bool
383 MTC_Slave::locked () const
384 {
385         return port->input()->mtc_locked();
386 }
387
388 bool
389 MTC_Slave::ok() const
390 {
391         return true;
392 }
393
394 bool
395 MTC_Slave::speed_and_position (double& speed, nframes64_t& pos)
396 {
397         nframes64_t now = session.engine().frame_time();
398         SafeTime last;
399         nframes_t elapsed;
400
401         read_current (&last);
402
403         if (last.timestamp == 0) {
404                 speed = 0;
405                 pos = last.position;
406                 DEBUG_TRACE (DEBUG::MTC, string_compose ("first call to MTC_Slave::speed_and_position, pos = %1\n", last.position));
407                 return true;
408         }
409
410         /* no timecode for 1/4 second ? conclude that its stopped */
411
412         if (last_inbound_frame && now > last_inbound_frame && now - last_inbound_frame > session.frame_rate() / 4) {
413                 speed = 0;
414                 pos = last.position;
415                 session.request_locate (pos, false);
416                 session.request_transport_speed (0);
417                 queue_reset ();
418                 DEBUG_TRACE (DEBUG::MTC, "MTC not seen for 1/4 second - reset pending\n");
419                 return false;
420         }
421
422         DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC::speed_and_position %1 %2\n", last.speed, last.position));
423
424         if (give_slave_full_control_over_transport_speed()) {
425             bool in_control = (session.slave_state() == Session::Running);
426             nframes64_t pic_want_locate = 0; 
427             //nframes64_t slave_pos = session.audible_frame();
428             nframes64_t slave_pos = session.transport_frame();
429             static double average_speed = 0;
430
431             average_speed = pic->get_ratio (last.timestamp, last.position, slave_pos, in_control );
432             pic_want_locate = pic->want_locate();
433
434             if (in_control && pic_want_locate) {
435                 last.speed = average_speed + (double) (pic_want_locate - session.transport_frame()) / (double)session.get_block_size();
436                 std::cout << "locate req " << pic_want_locate << " speed: " << average_speed << "\n"; 
437             } else {
438                 last.speed = average_speed;
439             }
440         }
441
442         if (last.speed == 0.0f) {
443
444                 elapsed = 0;
445
446         } else {
447
448                 /* scale elapsed time by the current MTC speed */
449
450                 if (last.timestamp && (now > last.timestamp)) {
451                         elapsed = (nframes_t) floor (last.speed * (now - last.timestamp));
452                         DEBUG_TRACE (DEBUG::MTC, string_compose ("last timecode received @ %1, now = %2, elapsed frames = %3 w/speed= %4\n",
453                                                                  last.timestamp, now, elapsed, last.speed));
454                 } else {
455                         elapsed = 0; /* XXX is this right? */
456                 }
457         }
458
459         /* now add the most recent timecode value plus the estimated elapsed interval */
460
461         pos = last.position + elapsed; 
462         speed = last.speed;
463
464         DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC::speed_and_position FINAL %1 %2\n", last.speed, pos));
465
466         return true;
467 }
468
469 ARDOUR::nframes_t
470 MTC_Slave::resolution() const
471 {
472         return (nframes_t) session.frames_per_timecode_frame();
473 }
474
475 void
476 MTC_Slave::queue_reset ()
477 {
478         Glib::Mutex::Lock lm (reset_lock);
479         reset_pending++;
480 }
481
482 void
483 MTC_Slave::maybe_reset ()
484 {
485         reset_lock.lock ();
486
487         if (reset_pending) {
488                 reset ();
489                 reset_pending = 0;
490         } 
491
492         reset_lock.unlock ();
493 }
494
495 void
496 MTC_Slave::reset ()
497 {
498         port->input()->reset_mtc_state ();
499
500         last_inbound_frame = 0;
501         current.guard1++;
502         current.position = 0;
503         current.timestamp = 0;
504         current.speed = 0;
505         current.guard2++;
506
507         window_begin = 0;
508         window_end = 0;
509         last_mtc_frame = 0;
510         last_mtc_timestamp = 0;
511
512         average_speed = 0;
513         have_first_speed_accumulator = false;
514         speed_accumulator_cnt = 0;
515
516         pic->reset();
517 }
518
519 void
520 MTC_Slave::reset_window (nframes64_t root)
521 {
522         
523         /* if we're waiting for the master to catch us after seeking ahead, keep the window
524            of acceptable MTC frames wide open. otherwise, shrink it down to just 2 video frames
525            ahead of the window root (taking direction into account).
526         */
527
528         switch (port->input()->mtc_running()) {
529         case MTC_Forward:
530                 window_begin = root;
531                 if (session.slave_state() == Session::Running) {
532                         window_end = root + (session.frames_per_timecode_frame() * frame_tolerance);
533                 } else {
534                         window_end = root + seekahead_distance ();
535                 }
536                 DEBUG_TRACE (DEBUG::MTC, string_compose ("legal MTC window now %1 .. %2\n", window_begin, window_end));
537                 break;
538
539         case MTC_Backward:
540                 if (session.slave_state() == Session::Running) {
541                         nframes_t d = session.frames_per_timecode_frame() * frame_tolerance;
542                         if (root > d) {
543                                 window_begin = root - d;
544                                 window_end = root;
545                         } else {
546                                 window_begin = 0;
547                         }
548                 } else {
549                         nframes_t d = seekahead_distance ();
550                         if (root > d) {
551                                 window_begin = root - d;
552                         } else {
553                                 window_begin = 0;
554                         }
555                 }
556                 window_end = root;
557                 DEBUG_TRACE (DEBUG::MTC, string_compose ("legal MTC window now %1 .. %2\n", window_begin, window_end));
558                 break;
559                 
560         default:
561                 /* do nothing */
562                 break;
563         }
564 }
565
566 nframes64_t
567 MTC_Slave::seekahead_distance () const
568 {
569         /* 1 second */
570         return session.frame_rate();
571 }
572
573 bool
574 MTC_Slave::outside_window (nframes64_t pos) const
575 {
576         return ((pos < window_begin) || (pos > window_end));
577 }