make note overlap resolution store side effects in a DiffCommand, and add its changes...
[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 = 0;
60         reset_position = false;
61
62         pic = new PIChaser();
63         
64         last_mtc_fps_byte = session.get_mtc_timecode_bits ();
65         mtc_frame = 0;
66
67         speed_accumulator_size = 16;
68         speed_accumulator = new double[speed_accumulator_size];
69
70         rebind (p);
71         reset (true);
72 }
73
74 MTC_Slave::~MTC_Slave()
75 {
76         if (did_reset_tc_format) {
77                 session.config.set_timecode_format (saved_tc_format);
78         }
79
80         delete pic;
81         delete [] speed_accumulator;
82 }
83
84 bool 
85 MTC_Slave::give_slave_full_control_over_transport_speed() const
86 {
87         return true; // for PiC control */
88         // return false; // for Session-level computed varispeed
89 }
90
91 void
92 MTC_Slave::rebind (MIDI::Port& p)
93 {
94         port_connections.drop_connections ();
95         
96         port = &p;
97         
98         port->input()->mtc_time.connect_same_thread (port_connections,  boost::bind (&MTC_Slave::update_mtc_time, this, _1, _2, _3));
99         port->input()->mtc_qtr.connect_same_thread (port_connections, boost::bind (&MTC_Slave::update_mtc_qtr, this, _1, _2, _3));
100         port->input()->mtc_status.connect_same_thread (port_connections, boost::bind (&MTC_Slave::update_mtc_status, this, _1));
101 }
102
103 void
104 MTC_Slave::update_mtc_qtr (Parser& /*p*/, int which_qtr, nframes_t now)
105 {
106         DEBUG_TRACE (DEBUG::MTC, string_compose ("qtr frame %1 at %2\n", which_qtr, now));
107         maybe_reset ();
108         last_inbound_frame = now;
109 }
110
111 void
112 MTC_Slave::update_mtc_time (const byte *msg, bool was_full, nframes_t now)
113 {
114         /* "now" can be zero if this is called from a context where we do not have or do not want
115            to use a timestamp indicating when this MTC time was received. example: when we received
116            a locate command via MMC.
117         */
118
119         if (now) {
120                 maybe_reset ();
121         }
122
123         Timecode::Time timecode;
124         TimecodeFormat tc_format;
125         bool reset_tc = true;
126         nframes64_t window_root = -1;
127
128         DEBUG_TRACE (DEBUG::MTC, string_compose ("full mtc time known at %1, full ? %2\n", now, was_full));
129         
130         timecode.hours = msg[3];
131         timecode.minutes = msg[2];
132         timecode.seconds = msg[1];
133         timecode.frames = msg[0];
134
135         last_mtc_fps_byte = msg[4];
136
137         switch (msg[4]) {
138         case MTC_24_FPS:
139                 timecode.rate = 24;
140                 timecode.drop = false;
141                 tc_format = timecode_24;
142                 can_notify_on_unknown_rate = true;
143                 break;
144         case MTC_25_FPS:
145                 timecode.rate = 25;
146                 timecode.drop = false;
147                 tc_format = timecode_25;
148                 can_notify_on_unknown_rate = true;
149                 break;
150         case MTC_30_FPS_DROP:
151                 timecode.rate = 30;
152                 timecode.drop = true;
153                 tc_format = timecode_30drop;
154                 can_notify_on_unknown_rate = true;
155                 break;
156         case MTC_30_FPS:
157                 timecode.rate = 30;
158                 timecode.drop = false;
159                 can_notify_on_unknown_rate = true;
160                 tc_format = timecode_30;
161                 break;
162         default:
163                 /* throttle error messages about unknown MTC rates */
164                 if (can_notify_on_unknown_rate) {
165                         error << string_compose (_("Unknown rate/drop value %1 in incoming MTC stream, session values used instead"),
166                                                  (int) msg[4])
167                               << endmsg;
168                         can_notify_on_unknown_rate = false;
169                 }
170                 timecode.rate = session.timecode_frames_per_second();
171                 timecode.drop = session.timecode_drop_frames();
172                 reset_tc = false;
173         }
174
175         if (reset_tc) {
176                 if (!did_reset_tc_format) {
177                         saved_tc_format = session.config.get_timecode_format();
178                         did_reset_tc_format = true;
179                 }
180                 session.config.set_timecode_format (tc_format);
181         }
182
183         DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC time timestamp = %1 TC %2 = frame %3 (from full message ? %4)\n", 
184                                                  now, timecode, mtc_frame, was_full));
185         
186         if (was_full || outside_window (mtc_frame)) {
187
188                 session.timecode_to_sample (timecode, mtc_frame, true, false);
189                 session.request_locate (mtc_frame, false);
190                 session.request_transport_speed (0);
191                 update_mtc_status (MIDI::MTC_Stopped);
192                 reset (false);
193                 reset_window (mtc_frame);
194
195         } else {
196                         
197                 /* we've had the first set of 8 qtr frame messages, determine position
198                    and allow continuing qtr frame messages to provide position
199                    and speed information.
200                 */
201                 
202                 /* do a careful conversion of the timecode value to a position
203                    so that we take drop/nondrop and all that nonsense into 
204                    consideration.
205                 */
206
207                 session.timecode_to_sample (timecode, mtc_frame, true, false);
208                 
209                 /* We received the last quarter frame 7 quarter frames (1.75 mtc
210                    frames) after the instance when the contents of the mtc quarter
211                    frames were decided. Add time to compensate for the elapsed 1.75
212                    frames. Also compensate for audio latency.
213                 */
214                 
215                 mtc_frame += (long) (1.75 * session.frames_per_timecode_frame()) + session.worst_output_latency();
216
217
218                 if (now) {
219
220                         if (last_mtc_timestamp == 0) {
221
222                                 last_mtc_timestamp = now;
223                                 last_mtc_frame = mtc_frame;
224
225                         } else {
226
227                                 if (give_slave_full_control_over_transport_speed()) {
228                                         /* PIC 
229                                          * 
230                                          * its not the average, but we will assign it to current.speed below
231                                          */
232
233                                     static nframes64_t last_seen_timestamp = 0; 
234                                     static nframes64_t last_seen_position = 0; 
235
236                                     if ((now - last_seen_timestamp) < 300) {
237                                         mtc_frame = (mtc_frame + last_seen_position)/2;
238                                     }
239
240                                     last_seen_timestamp = now;
241                                     last_seen_position = mtc_frame;
242
243                                         
244                                         
245                                 } else {
246
247                                         /* Non-PiC 
248                                          */
249
250                                         nframes64_t time_delta = (now - last_mtc_timestamp);
251                                         
252                                         if (time_delta != 0) {
253                                                 double apparent_speed = (mtc_frame - last_mtc_frame) / (double) (time_delta);
254                                                 
255                                                 process_apparent_speed (apparent_speed);
256                                                 DEBUG_TRACE (DEBUG::Slave, string_compose ("apparent speed was %1 average is now %2\n", apparent_speed, average_speed));
257                                         } else {
258                                                 DEBUG_TRACE (DEBUG::Slave, string_compose ("no apparent calc, average is %1\n", average_speed));
259                                         }
260                                         
261                                         /* every second, recalibrate the starting point for the speed measurement */
262                                         if (mtc_frame - last_mtc_frame > session.frame_rate()) {
263                                                 last_mtc_timestamp = now;
264                                                 last_mtc_frame = mtc_frame;
265                                         }
266                                 }
267                         }
268
269                         current.guard1++;
270                         current.position = mtc_frame;
271                         current.timestamp = now;
272                         current.speed = average_speed;
273                         current.guard2++;
274                         window_root = mtc_frame;
275                 }
276         }
277
278         if (now) {
279                 last_inbound_frame = now;
280         }
281
282         if (window_root >= 0) {
283                 reset_window (window_root);
284         }
285 }
286
287 void
288 MTC_Slave::process_apparent_speed (double this_speed)
289 {
290         DEBUG_TRACE (DEBUG::MTC, string_compose ("speed cnt %1 sz %2 have %3\n", speed_accumulator_cnt, speed_accumulator_size, have_first_speed_accumulator));
291
292         /* clamp to an expected range */
293
294         if (this_speed > 4.0 || this_speed < -4.0) {
295                 this_speed = average_speed;
296         }
297
298         if (speed_accumulator_cnt >= speed_accumulator_size) {
299                 have_first_speed_accumulator = true;
300                 speed_accumulator_cnt = 0;
301         }
302
303         speed_accumulator[speed_accumulator_cnt++] = this_speed;
304
305         if (have_first_speed_accumulator) {
306                 average_speed = 0.0;
307                 for (size_t i = 0; i < speed_accumulator_size; ++i) {
308                         average_speed += speed_accumulator[i];
309                 }
310                 average_speed /= speed_accumulator_size;
311         }
312 }
313
314 void
315 MTC_Slave::handle_locate (const MIDI::byte* mmc_tc)
316 {
317         MIDI::byte mtc[5];
318
319         mtc[4] = last_mtc_fps_byte;
320         mtc[3] = mmc_tc[0] & 0xf; /* hrs only */
321         mtc[2] = mmc_tc[1];
322         mtc[1] = mmc_tc[2];
323         mtc[0] = mmc_tc[3];
324
325         update_mtc_time (mtc, true, 0);
326 }
327
328 void
329 MTC_Slave::update_mtc_status (MIDI::MTC_Status status)
330 {
331         /* XXX !!! thread safety ... called from MIDI I/O context
332            and process() context (via ::speed_and_position())
333         */
334
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         bool in_control = false;
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 (false);
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                 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                 nframes64_t ref_now = session.engine().frame_time_at_cycle_start();
432                 average_speed = pic->get_ratio (last.timestamp, last.position, ref_now, slave_pos, in_control, session.engine().frames_per_cycle());
433   
434                 pic_want_locate = pic->want_locate();
435                 
436                 if (in_control && pic_want_locate) {
437                         last.speed = average_speed + (double) (pic_want_locate - session.transport_frame()) / (double)session.get_block_size();
438                         std::cout << "locate req " << pic_want_locate << " speed: " << average_speed << "\n"; 
439                 } else {
440                         last.speed = average_speed;
441                 }
442         }
443
444         if (last.speed == 0.0f) {
445
446                 elapsed = 0;
447
448         } else {
449
450                 /* scale elapsed time by the current MTC speed */
451
452                 if (last.timestamp && (now > last.timestamp)) {
453                         elapsed = (nframes_t) floor (last.speed * (now - last.timestamp));
454                         DEBUG_TRACE (DEBUG::MTC, string_compose ("last timecode received @ %1, now = %2, elapsed frames = %3 w/speed= %4\n",
455                                                                  last.timestamp, now, elapsed, last.speed));
456                 } else {
457                         elapsed = 0; /* XXX is this right? */
458                 }
459         }
460
461         /* now add the most recent timecode value plus the estimated elapsed interval */
462
463         if (in_control) {
464                 pos = session.transport_frame();
465         } else {
466                 pos = last.position + elapsed; 
467         }
468
469         speed = last.speed;
470
471         DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC::speed_and_position FINAL %1 %2\n", last.speed, pos));
472
473         return true;
474 }
475
476 ARDOUR::nframes_t
477 MTC_Slave::resolution() const
478 {
479         return (nframes_t) session.frames_per_timecode_frame();
480 }
481
482 void
483 MTC_Slave::queue_reset (bool reset_pos)
484 {
485         Glib::Mutex::Lock lm (reset_lock);
486         reset_pending++;
487         if (reset_pos) {
488                 reset_position = true;
489         }
490 }
491
492 void
493 MTC_Slave::maybe_reset ()
494 {
495         Glib::Mutex::Lock lm (reset_lock);
496
497         if (reset_pending) {
498                 reset (reset_position);
499                 reset_pending = 0;
500                 reset_position = false;
501         } 
502 }
503
504 void
505 MTC_Slave::reset (bool with_position)
506 {
507         if (with_position) {
508                 last_inbound_frame = 0;
509                 current.guard1++;
510                 current.position = 0;
511                 current.timestamp = 0;
512                 current.speed = 0;
513                 current.guard2++;
514         } else {
515                 last_inbound_frame = 0;
516                 current.guard1++;
517                 current.timestamp = 0;
518                 current.speed = 0;
519                 current.guard2++;
520         }
521
522         window_begin = 0;
523         window_end = 0;
524         last_mtc_frame = 0;
525         last_mtc_timestamp = 0;
526
527         average_speed = 0;
528         have_first_speed_accumulator = false;
529         speed_accumulator_cnt = 0;
530
531         pic->reset();
532 }
533
534 void
535 MTC_Slave::reset_window (nframes64_t root)
536 {
537         
538         /* if we're waiting for the master to catch us after seeking ahead, keep the window
539            of acceptable MTC frames wide open. otherwise, shrink it down to just 2 video frames
540            ahead of the window root (taking direction into account).
541         */
542
543         switch (port->input()->mtc_running()) {
544         case MTC_Forward:
545                 window_begin = root;
546                 if (session.slave_state() == Session::Running) {
547                         window_end = root + (session.frames_per_timecode_frame() * frame_tolerance);
548                 } else {
549                         window_end = root + seekahead_distance ();
550                 }
551                 break;
552
553         case MTC_Backward:
554                 if (session.slave_state() == Session::Running) {
555                         nframes_t d = session.frames_per_timecode_frame() * frame_tolerance;
556                         if (root > d) {
557                                 window_begin = root - d;
558                                 window_end = root;
559                         } else {
560                                 window_begin = 0;
561                         }
562                 } else {
563                         nframes_t d = seekahead_distance ();
564                         if (root > d) {
565                                 window_begin = root - d;
566                         } else {
567                                 window_begin = 0;
568                         }
569                 }
570                 window_end = root;
571                 break;
572                 
573         default:
574                 /* do nothing */
575                 break;
576         }
577
578         DEBUG_TRACE (DEBUG::MTC, string_compose ("legal MTC window now %1 .. %2\n", window_begin, window_end));
579 }
580
581 nframes64_t
582 MTC_Slave::seekahead_distance () const
583 {
584         /* 1 second */
585         return session.frame_rate();
586 }
587
588 bool
589 MTC_Slave::outside_window (nframes64_t pos) const
590 {
591         return ((pos < window_begin) || (pos > window_end));
592 }