Add option to limit automatable control parmaters
[ardour.git] / libs / ardour / mtc_slave.cc
1 /*
2     Copyright (C) 2002-4 Paul Davis
3     Overhaul 2012 Robin Gareus <robin@gareus.org>
4
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14
15     You should have received a copy of the GNU General Public License
16     along with this program; if not, write to the Free Software
17     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18
19 */
20 #include <iostream>
21 #include <errno.h>
22 #include <sys/types.h>
23 #include <unistd.h>
24
25 #include "pbd/error.h"
26 #include "pbd/pthread_utils.h"
27
28 #include "ardour/audioengine.h"
29 #include "ardour/debug.h"
30 #include "ardour/midi_buffer.h"
31 #include "ardour/midi_port.h"
32 #include "ardour/session.h"
33 #include "ardour/transport_master.h"
34
35 #include "pbd/i18n.h"
36
37 using namespace std;
38 using namespace ARDOUR;
39 using namespace MIDI;
40 using namespace PBD;
41 using namespace Timecode;
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 const int MTC_TransportMaster::sample_tolerance = 2;
51
52 MTC_TransportMaster::MTC_TransportMaster (std::string const & name)
53         : TimecodeTransportMaster (name, MTC)
54         , can_notify_on_unknown_rate (true)
55         , mtc_frame (0)
56         , mtc_frame_dll (0)
57         , last_inbound_frame (0)
58         , window_begin (0)
59         , window_end (0)
60         , first_mtc_timestamp (0)
61         , did_reset_tc_format (false)
62         , reset_pending (0)
63         , reset_position (false)
64         , transport_direction (1)
65         , busy_guard1 (0)
66         , busy_guard2 (0)
67         , printed_timecode_warning (false)
68 {
69         if ((_port = create_midi_port (string_compose ("%1 in", name))) == 0) {
70                 throw failed_constructor();
71         }
72
73         DEBUG_TRACE (DEBUG::Slave, string_compose ("MTC registered %1\n", _port->name()));
74
75         init ();
76 }
77
78 MTC_TransportMaster::~MTC_TransportMaster()
79 {
80         port_connections.drop_connections();
81         config_connection.disconnect();
82
83         while (busy_guard1 != busy_guard2) {
84                 /* make sure MIDI parser is not currently calling any callbacks in here,
85                  * else there's a segfault ahead!
86                  *
87                  * XXX this is called from jack rt-context :(
88                  * TODO fix libs/ardour/session_transport.cc:1321 (delete _slave;)
89                  */
90                 sched_yield();
91         }
92
93         if (did_reset_tc_format) {
94                 _session->config.set_timecode_format (saved_tc_format);
95         }
96 }
97
98 void
99 MTC_TransportMaster::init ()
100 {
101         reset (true);
102 }
103
104 void
105 MTC_TransportMaster::set_session (Session *s)
106 {
107         config_connection.disconnect ();
108         port_connections.drop_connections();
109
110         _session = s;
111
112         if (_session) {
113
114                 last_mtc_fps_byte = _session->get_mtc_timecode_bits ();
115                 quarter_frame_duration = (double) (_session->samples_per_timecode_frame() / 4.0);
116                 mtc_timecode = _session->config.get_timecode_format();
117                 a3e_timecode = _session->config.get_timecode_format();
118
119                 parse_timecode_offset ();
120                 reset (true);
121
122                 parser.mtc_time.connect_same_thread (port_connections,  boost::bind (&MTC_TransportMaster::update_mtc_time, this, _1, _2, _3));
123                 parser.mtc_qtr.connect_same_thread (port_connections, boost::bind (&MTC_TransportMaster::update_mtc_qtr, this, _1, _2, _3));
124                 parser.mtc_status.connect_same_thread (port_connections, boost::bind (&MTC_TransportMaster::update_mtc_status, this, _1));
125
126                 _session->config.ParameterChanged.connect_same_thread (config_connection, boost::bind (&MTC_TransportMaster::parameter_changed, this, _1));
127         }
128 }
129
130 void
131 MTC_TransportMaster::pre_process (MIDI::pframes_t nframes, samplepos_t now, boost::optional<samplepos_t> session_pos)
132 {
133         /* Read and parse incoming MIDI */
134
135         maybe_reset ();
136
137         _midi_port->read_and_parse_entire_midi_buffer_with_no_speed_adjustment (nframes, parser, now);
138
139         if (session_pos) {
140                 const samplepos_t current_pos = current.position + ((now - current.timestamp) * current.speed);
141                 _current_delta = current_pos - *session_pos;
142         } else {
143                 _current_delta = 0;
144         }
145 }
146
147 void
148 MTC_TransportMaster::parse_timecode_offset() {
149         Timecode::Time offset_tc;
150         Timecode::parse_timecode_format (_session->config.get_slave_timecode_offset(), offset_tc);
151         offset_tc.rate = _session->timecode_frames_per_second();
152         offset_tc.drop = _session->timecode_drop_frames();
153         _session->timecode_to_sample(offset_tc, timecode_offset, false, false);
154         timecode_negative_offset = offset_tc.negative;
155 }
156
157 void
158 MTC_TransportMaster::parameter_changed (std::string const & p)
159 {
160         if (p == "slave-timecode-offset"
161                         || p == "timecode-format"
162                         ) {
163                 parse_timecode_offset();
164         }
165 }
166
167 ARDOUR::samplecnt_t
168 MTC_TransportMaster::update_interval() const
169 {
170         if (timecode.rate) {
171                 return AudioEngine::instance()->sample_rate() / timecode.rate;
172         }
173
174         return AudioEngine::instance()->sample_rate(); /* useless but what other answer is there? */
175 }
176
177 ARDOUR::samplecnt_t
178 MTC_TransportMaster::resolution () const
179 {
180         return (samplecnt_t) quarter_frame_duration * 4.0;
181 }
182
183 ARDOUR::samplecnt_t
184 MTC_TransportMaster::seekahead_distance () const
185 {
186         return quarter_frame_duration * 8 * transport_direction;
187 }
188
189 bool
190 MTC_TransportMaster::outside_window (samplepos_t pos) const
191 {
192         return ((pos < window_begin) || (pos > window_end));
193 }
194
195
196 bool
197 MTC_TransportMaster::locked () const
198 {
199         DEBUG_TRACE (DEBUG::MTC, string_compose ("locked ? %1 last %2\n", parser.mtc_locked(), last_inbound_frame));
200         return parser.mtc_locked() && last_inbound_frame !=0;
201 }
202
203 bool
204 MTC_TransportMaster::ok() const
205 {
206         return true;
207 }
208
209 void
210 MTC_TransportMaster::queue_reset (bool reset_pos)
211 {
212         Glib::Threads::Mutex::Lock lm (reset_lock);
213         reset_pending++;
214         if (reset_pos) {
215                 reset_position = true;
216         }
217 }
218
219 void
220 MTC_TransportMaster::maybe_reset ()
221 {
222         Glib::Threads::Mutex::Lock lm (reset_lock);
223
224         if (reset_pending) {
225                 reset (reset_position);
226                 reset_pending = 0;
227                 reset_position = false;
228         }
229 }
230
231 void
232 MTC_TransportMaster::reset (bool with_position)
233 {
234         DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC_TransportMaster reset %1\n", with_position?"with position":"without position"));
235
236         if (with_position) {
237                 current.update (0, 0, 0);
238         } else {
239                 current.update (current.position, 0, 0);
240         }
241         first_mtc_timestamp = 0;
242         window_begin = 0;
243         window_end = 0;
244         transport_direction = 1;
245         _current_delta = 0;
246 }
247
248 void
249 MTC_TransportMaster::handle_locate (const MIDI::byte* mmc_tc)
250 {
251         MIDI::byte mtc[5];
252         DEBUG_TRACE (DEBUG::MTC, "MTC_TransportMaster::handle_locate\n");
253
254         mtc[4] = last_mtc_fps_byte;
255         mtc[3] = mmc_tc[0] & 0xf; /* hrs only */
256         mtc[2] = mmc_tc[1];
257         mtc[1] = mmc_tc[2];
258         mtc[0] = mmc_tc[3];
259
260         update_mtc_time (mtc, true, 0);
261 }
262
263 void
264 MTC_TransportMaster::init_mtc_dll(samplepos_t tme, double qtr)
265 {
266         const double omega = 2.0 * M_PI * qtr / 2.0 / double(_session->sample_rate());
267         b = 1.4142135623730950488 * omega;
268         c = omega * omega;
269
270         e2 = qtr;
271         t0 = double(tme);
272         t1 = t0 + e2;
273         DEBUG_TRACE (DEBUG::MTC, string_compose ("[re-]init MTC DLL %1 %2 %3\n", t0, t1, e2));
274 }
275
276 /* called from MIDI parser */
277 void
278 MTC_TransportMaster::update_mtc_qtr (Parser& p, int which_qtr, samplepos_t now)
279 {
280         busy_guard1++;
281         const double qtr_d = quarter_frame_duration;
282
283         mtc_frame_dll += qtr_d * (double) transport_direction;
284         mtc_frame = rint(mtc_frame_dll);
285
286         DEBUG_TRACE (DEBUG::MTC, string_compose ("qtr sample %1 at %2 -> mtc_frame: %3\n", which_qtr, now, mtc_frame));
287
288         double mtc_speed = 0;
289         if (first_mtc_timestamp != 0) {
290                 /* update MTC DLL and calculate speed */
291                 const double e = mtc_frame_dll - (double)transport_direction * ((double)now - (double)current.timestamp + t0);
292                 t0 = t1;
293                 t1 += b * e + e2;
294                 e2 += c * e;
295
296                 mtc_speed = (t1 - t0) / qtr_d;
297                 DEBUG_TRACE (DEBUG::MTC, string_compose ("qtr sample DLL t0:%1 t1:%2 err:%3 spd:%4 ddt:%5\n", t0, t1, e, mtc_speed, e2 - qtr_d));
298
299                 current.update (mtc_frame, now, mtc_speed);
300
301                 last_inbound_frame = now;
302         }
303
304         maybe_reset ();
305
306         busy_guard2++;
307 }
308
309 /* called from MIDI parser _after_ update_mtc_qtr()
310  * when a full TC has been received
311  * OR on locate */
312 void
313 MTC_TransportMaster::update_mtc_time (const MIDI::byte *msg, bool was_full, samplepos_t now)
314 {
315         busy_guard1++;
316
317         /* "now" can be zero if this is called from a context where we do not have or do not want
318            to use a timestamp indicating when this MTC time was received. example: when we received
319            a locate command via MMC.
320         */
321         DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC::update_mtc_time - TID:%1\n", pthread_name()));
322         TimecodeFormat tc_format;
323         bool reset_tc = true;
324
325         timecode.hours = msg[3];
326         timecode.minutes = msg[2];
327         timecode.seconds = msg[1];
328         timecode.frames = msg[0];
329
330         last_mtc_fps_byte = msg[4];
331
332         DEBUG_TRACE (DEBUG::MTC, string_compose ("full mtc time known at %1, full ? %2\n", now, was_full));
333
334         if (now) {
335                 maybe_reset ();
336         }
337
338         switch (msg[4]) {
339         case MTC_24_FPS:
340                 timecode.rate = 24;
341                 timecode.drop = false;
342                 tc_format = timecode_24;
343                 can_notify_on_unknown_rate = true;
344                 break;
345         case MTC_25_FPS:
346                 timecode.rate = 25;
347                 timecode.drop = false;
348                 tc_format = timecode_25;
349                 can_notify_on_unknown_rate = true;
350                 break;
351         case MTC_30_FPS_DROP:
352                 if (fr2997()) {
353                         tc_format = Timecode::timecode_2997000drop;
354                         timecode.rate = (29970.0/1000.0);
355                 } else {
356                         tc_format = timecode_2997drop;
357                         timecode.rate = (30000.0/1001.0);
358                 }
359                 timecode.drop = true;
360                 can_notify_on_unknown_rate = true;
361                 break;
362         case MTC_30_FPS:
363                 timecode.rate = 30;
364                 timecode.drop = false;
365                 can_notify_on_unknown_rate = true;
366                 tc_format = timecode_30;
367                 break;
368         default:
369                 /* throttle error messages about unknown MTC rates */
370                 if (can_notify_on_unknown_rate) {
371                         error << string_compose (_("Unknown rate/drop value %1 in incoming MTC stream, session values used instead"),
372                                                  (int) msg[4])
373                               << endmsg;
374                         can_notify_on_unknown_rate = false;
375                 }
376                 timecode.rate = _session->timecode_frames_per_second();
377                 timecode.drop = _session->timecode_drop_frames();
378                 reset_tc = false;
379         }
380
381         if (reset_tc) {
382                 TimecodeFormat cur_timecode = _session->config.get_timecode_format();
383                 if (Config->get_timecode_sync_frame_rate()) {
384                         /* enforce time-code */
385                         if (!did_reset_tc_format) {
386                                 saved_tc_format = cur_timecode;
387                                 did_reset_tc_format = true;
388                         }
389                         if (cur_timecode != tc_format) {
390                                 if (ceil(Timecode::timecode_to_frames_per_second(cur_timecode)) != ceil(Timecode::timecode_to_frames_per_second(tc_format))) {
391                                         warning << string_compose(_("Session framerate adjusted from %1 TO: MTC's %2."),
392                                                         Timecode::timecode_format_name(cur_timecode),
393                                                         Timecode::timecode_format_name(tc_format))
394                                                 << endmsg;
395                                 }
396                         }
397                         _session->config.set_timecode_format (tc_format);
398                 } else {
399                         /* only warn about TC mismatch */
400                         if (mtc_timecode != tc_format) printed_timecode_warning = false;
401                         if (a3e_timecode != cur_timecode) printed_timecode_warning = false;
402
403                         if (cur_timecode != tc_format && ! printed_timecode_warning) {
404                                 if (ceil(Timecode::timecode_to_frames_per_second(cur_timecode)) != ceil(Timecode::timecode_to_frames_per_second(tc_format))) {
405                                         warning << string_compose(_("Session and MTC framerate mismatch: MTC:%1 %2:%3."),
406                                                                   Timecode::timecode_format_name(tc_format),
407                                                                   PROGRAM_NAME,
408                                                                   Timecode::timecode_format_name(cur_timecode))
409                                                 << endmsg;
410                                 }
411                                 printed_timecode_warning = true;
412                         }
413                 }
414                 mtc_timecode = tc_format;
415                 a3e_timecode = cur_timecode;
416
417                 speedup_due_to_tc_mismatch = timecode.rate / Timecode::timecode_to_frames_per_second(a3e_timecode);
418         }
419
420         /* do a careful conversion of the timecode value to a position
421            so that we take drop/nondrop and all that nonsense into
422            consideration.
423         */
424
425         quarter_frame_duration = (double(_session->sample_rate()) / (double) timecode.rate / 4.0);
426
427         Timecode::timecode_to_sample (timecode, mtc_frame, true, false,
428                 double(_session->sample_rate()),
429                 _session->config.get_subframes_per_frame(),
430                 timecode_negative_offset, timecode_offset
431                 );
432
433         DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC at %1 TC %2 = mtc_frame %3 (from full message ? %4) tc-ratio %5\n",
434                                                  now, timecode, mtc_frame, was_full, speedup_due_to_tc_mismatch));
435
436         if (was_full || outside_window (mtc_frame)) {
437                 DEBUG_TRACE (DEBUG::MTC, string_compose ("update_mtc_time: full TC %1 or outside window %2 MTC %3\n", was_full, outside_window (mtc_frame), mtc_frame));
438                 _session->set_requested_return_sample (-1);
439                 _session->request_transport_speed (0, TRS_MTC);
440                 _session->request_locate (mtc_frame, false, TRS_MTC);
441                 update_mtc_status (MIDI::MTC_Stopped);
442                 reset (false);
443                 reset_window (mtc_frame);
444         } else {
445
446                 /* we've had the first set of 8 qtr sample messages, determine position
447                    and allow continuing qtr sample messages to provide position
448                    and speed information.
449                 */
450
451                 /* We received the last quarter frame 7 quarter frames (1.75 mtc
452                    samples) after the instance when the contents of the mtc quarter
453                    samples were decided. Add time to compensate for the elapsed 1.75
454                    samples.
455                 */
456                 double qtr = quarter_frame_duration;
457                 long int mtc_off = (long) rint(7.0 * qtr);
458
459                 DEBUG_TRACE (DEBUG::MTC, string_compose ("new mtc_frame: %1 | MTC-FpT: %2 A3-FpT:%3\n",
460                                                          mtc_frame, (4.0*qtr), _session->samples_per_timecode_frame()));
461
462                 switch (parser.mtc_running()) {
463                 case MTC_Backward:
464                         mtc_frame -= mtc_off;
465                         qtr *= -1.0;
466                         break;
467                 case MTC_Forward:
468                         mtc_frame += mtc_off;
469                         break;
470                 default:
471                         break;
472                 }
473
474                 DEBUG_TRACE (DEBUG::MTC, string_compose ("new mtc_frame (w/offset) = %1\n", mtc_frame));
475
476                 if (now) {
477                         if (first_mtc_timestamp == 0 || current.timestamp == 0) {
478                                 first_mtc_timestamp = now;
479                                 init_mtc_dll(mtc_frame, qtr);
480                                 mtc_frame_dll = mtc_frame;
481                         }
482                         current.update (mtc_frame, now, current.speed);
483                         reset_window (mtc_frame);
484                 }
485         }
486
487         busy_guard2++;
488 }
489
490 void
491 MTC_TransportMaster::update_mtc_status (MIDI::MTC_Status status)
492 {
493         /* XXX !!! thread safety ... called from MIDI I/O context
494          * on locate (via ::update_mtc_time())
495          */
496         DEBUG_TRACE (DEBUG::MTC, string_compose("MTC_TransportMaster::update_mtc_status - TID:%1 MTC:%2\n", pthread_name(), mtc_frame));
497         return; // why was this fn needed anyway ? it just messes up things -> use reset.
498         busy_guard1++;
499
500         switch (status) {
501         case MTC_Stopped:
502                 current.update (mtc_frame, 0, 0);
503                 break;
504
505         case MTC_Forward:
506                 current.update (mtc_frame, 0, 0);
507                 break;
508
509         case MTC_Backward:
510                 current.update (mtc_frame, 0, 0);
511                 break;
512         }
513         busy_guard2++;
514 }
515
516 void
517 MTC_TransportMaster::reset_window (samplepos_t root)
518 {
519         /* if we're waiting for the master to catch us after seeking ahead, keep the window
520            of acceptable MTC samples wide open. otherwise, shrink it down to just 2 video frames
521            ahead of the window root (taking direction into account).
522         */
523
524         samplecnt_t const d = (quarter_frame_duration * 4 * sample_tolerance);
525
526         switch (parser.mtc_running()) {
527         case MTC_Forward:
528                 window_begin = root;
529                 transport_direction = 1;
530                 window_end = root + d;
531                 break;
532
533         case MTC_Backward:
534                 transport_direction = -1;
535                 if (root > d) {
536                         window_begin = root - d;
537                         window_end = root;
538                 } else {
539                         window_begin = 0;
540                 }
541                 window_end = root;
542                 break;
543
544         default:
545                 /* do nothing */
546                 break;
547         }
548
549         DEBUG_TRACE (DEBUG::MTC, string_compose ("reset MTC window @ %3, now %1 .. %2\n", window_begin, window_end, root));
550 }
551
552 Timecode::TimecodeFormat
553 MTC_TransportMaster::apparent_timecode_format () const
554 {
555         return mtc_timecode;
556 }
557
558 std::string
559 MTC_TransportMaster::position_string() const
560 {
561         SafeTime last;
562         current.safe_read (last);
563         if (last.timestamp == 0 || reset_pending) {
564                 return " --:--:--:--";
565         }
566         return Timecode::timecode_format_sampletime(
567                 last.position,
568                 double(_session->sample_rate()),
569                 Timecode::timecode_to_frames_per_second(mtc_timecode),
570                 Timecode::timecode_has_drop_frames(mtc_timecode));
571 }
572
573 std::string
574 MTC_TransportMaster::delta_string () const
575 {
576         char delta[80];
577         SafeTime last;
578         current.safe_read (last);
579
580         delta[0] = '\0';
581
582         if (last.timestamp == 0 || reset_pending) {
583                 snprintf(delta, sizeof(delta), "\u2012\u2012\u2012\u2012");
584         } else {
585                 snprintf(delta, sizeof(delta), "\u0394<span foreground=\"green\" face=\"monospace\" >%s%s%" PRIi64 "</span>sm",
586                                 LEADINGZERO(abs(_current_delta)), PLUSMINUS(-_current_delta), abs(_current_delta));
587         }
588         return std::string(delta);
589 }