continue with MTC 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 #include "pbd/error.h"
25 #include "pbd/failed_constructor.h"
26 #include "pbd/pthread_utils.h"
27
28 #include "midi++/port.h"
29 #include "ardour/debug.h"
30 #include "ardour/slave.h"
31 #include "ardour/session.h"
32 #include "ardour/audioengine.h"
33 #include "ardour/cycles.h"
34
35 #include "i18n.h"
36
37 using namespace std;
38 using namespace ARDOUR;
39 using namespace sigc;
40 using namespace MIDI;
41 using namespace PBD;
42
43 MTC_Slave::MTC_Slave (Session& s, MIDI::Port& p)
44         : session (s)
45 {
46         can_notify_on_unknown_rate = true;
47         did_reset_tc_format = false;
48         
49         last_mtc_fps_byte = session.get_mtc_timecode_bits ();
50
51         rebind (p);
52         reset ();
53 }
54
55 MTC_Slave::~MTC_Slave()
56 {
57         if (did_reset_tc_format) {
58                 session.config.set_timecode_format (saved_tc_format);
59         }
60 }
61
62 void
63 MTC_Slave::rebind (MIDI::Port& p)
64 {
65         for (vector<sigc::connection>::iterator i = connections.begin(); i != connections.end(); ++i) {
66                 (*i).disconnect ();
67         }
68
69         port = &p;
70
71         connections.push_back (port->input()->mtc_time.connect (mem_fun (*this, &MTC_Slave::update_mtc_time)));
72         connections.push_back (port->input()->mtc_qtr.connect (mem_fun (*this, &MTC_Slave::update_mtc_qtr)));
73         connections.push_back (port->input()->mtc_status.connect (mem_fun (*this, &MTC_Slave::update_mtc_status)));
74 }
75
76 void
77 MTC_Slave::update_mtc_qtr (Parser& /*p*/, int which_qtr)
78 {
79         if (qtr_frame_messages_valid_for_time) {
80                 
81                 nframes64_t now = session.engine().frame_time();
82
83                 if (which_qtr != 7) {
84
85                         /* leave position and speed updates for the last
86                            qtr frame message of the 8 to be taken
87                            care of in update_mtc_time(), invoked
88                            by the Parser right after this.
89                         */
90
91                         nframes_t qtr;
92                         
93                         qtr = (long) (session.frames_per_timecode_frame() / 4);
94                         mtc_frame += qtr;
95                         
96                         double speed = compute_apparent_speed (now);
97                         
98                         current.guard1++;
99                         current.position = mtc_frame;
100                         current.timestamp = now;
101                         current.speed = speed;
102                         current.guard2++;
103                 }
104
105                 last_inbound_frame = now;
106         }
107 }
108
109 void
110 MTC_Slave::update_mtc_time (const byte *msg, bool was_full)
111 {
112         nframes64_t now = session.engine().frame_time();
113         Timecode::Time timecode;
114         TimecodeFormat tc_format;
115         bool reset_tc = true;
116
117         timecode.hours = msg[3];
118         timecode.minutes = msg[2];
119         timecode.seconds = msg[1];
120         timecode.frames = msg[0];
121
122         last_mtc_fps_byte = msg[4];
123
124         switch (msg[4]) {
125         case MTC_24_FPS:
126                 timecode.rate = 24;
127                 timecode.drop = false;
128                 tc_format = timecode_24;
129                 can_notify_on_unknown_rate = true;
130                 break;
131         case MTC_25_FPS:
132                 timecode.rate = 25;
133                 timecode.drop = false;
134                 tc_format = timecode_25;
135                 can_notify_on_unknown_rate = true;
136                 break;
137         case MTC_30_FPS_DROP:
138                 timecode.rate = 30;
139                 timecode.drop = true;
140                 tc_format = timecode_30drop;
141                 can_notify_on_unknown_rate = true;
142                 break;
143         case MTC_30_FPS:
144                 timecode.rate = 30;
145                 timecode.drop = false;
146                 can_notify_on_unknown_rate = true;
147                 tc_format = timecode_30;
148                 break;
149         default:
150                 /* throttle error messages about unknown MTC rates */
151                 if (can_notify_on_unknown_rate) {
152                         error << string_compose (_("Unknown rate/drop value %1 in incoming MTC stream, session values used instead"),
153                                                  (int) msg[4])
154                               << endmsg;
155                         can_notify_on_unknown_rate = false;
156                 }
157                 timecode.rate = session.timecode_frames_per_second();
158                 timecode.drop = session.timecode_drop_frames();
159                 reset_tc = false;
160         }
161
162         if (reset_tc) {
163                 if (!did_reset_tc_format) {
164                         saved_tc_format = session.config.get_timecode_format();
165                         did_reset_tc_format = true;
166                 }
167                 session.config.set_timecode_format (tc_format);
168         }
169
170         DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC time timestamp = %1 TC %2 = frame %3 (from full message ? %4)\n", 
171                                                  now, timecode, mtc_frame, was_full));
172
173         if (was_full) {
174
175                 session.timecode_to_sample (timecode, mtc_frame, true, false);
176                 session.request_locate (mtc_frame, false);
177                 session.request_transport_speed (0);
178                 update_mtc_status (MIDI::Parser::MTC_Stopped);
179
180                 reset ();
181
182         } else {
183
184                         
185                 /* we've had the first set of 8 qtr frame messages, determine position
186                            and allow continuing qtr frame messages to provide position
187                            and speed information.
188                 */
189                 
190                 qtr_frame_messages_valid_for_time = true;
191                 session.timecode_to_sample (timecode, mtc_frame, true, false);
192                 
193                 /* We received the last quarter frame 7 quarter frames (1.75 mtc
194                    frames) after the instance when the contents of the mtc quarter
195                    frames were decided. Add time to compensate for the elapsed 1.75
196                    frames. Also compensate for audio latency.
197                 */
198                 
199                 mtc_frame += (long) (1.75 * session.frames_per_timecode_frame()) + session.worst_output_latency();
200                 
201                 double speed = compute_apparent_speed (now);
202                 
203                 current.guard1++;
204                 current.position = mtc_frame;
205                 current.timestamp = now;
206                 current.speed = speed;
207                 current.guard2++;
208         }
209
210         last_inbound_frame = now;
211 }
212
213 double
214 MTC_Slave::compute_apparent_speed (nframes64_t now)
215 {
216         if (current.timestamp != 0) {
217                 
218                 double speed = (double) ((mtc_frame - current.position) / (double) (now - current.timestamp));
219                 DEBUG_TRACE (DEBUG::MTC, string_compose ("instantaneous speed = %1 from %2 - %3 / %4 - %5\n",
220                                                          speed, mtc_frame, current.position, now, current.timestamp));
221                 
222                 /* crude low pass filter/smoother for speed */
223
224                 accumulator[accumulator_index++] = speed;
225                 
226                 if (accumulator_index >= accumulator_size) {
227                         have_first_accumulated_speed = true;
228                         accumulator_index = 0;
229                 }
230                 
231                 if (have_first_accumulated_speed) {
232                         double total = 0;
233                         
234                         for (int32_t i = 0; i < accumulator_size; ++i) {
235                                 total += accumulator[i];
236                         }
237                         
238                         speed = total / accumulator_size;
239                         DEBUG_TRACE (DEBUG::MTC, string_compose ("speed smoothed to %1\n", speed));
240                 } 
241
242                 return speed;
243                 
244         } else {
245                 
246                 return 0;
247         }
248 }
249
250 void
251 MTC_Slave::handle_locate (const MIDI::byte* mmc_tc)
252 {
253         MIDI::byte mtc[5];
254
255         mtc[4] = last_mtc_fps_byte;
256         mtc[3] = mmc_tc[0] & 0xf; /* hrs only */
257         mtc[2] = mmc_tc[1];
258         mtc[1] = mmc_tc[2];
259         mtc[0] = mmc_tc[3];
260
261         update_mtc_time (mtc, true);
262 }
263
264 void
265 MTC_Slave::update_mtc_status (MIDI::Parser::MTC_Status status)
266 {
267         /* XXX !!! thread safety ... called from MIDI I/O context
268            and process() context (via ::speed_and_position())
269         */
270
271         switch (status) {
272         case MTC_Stopped:
273                 mtc_frame = 0;
274
275                 current.guard1++;
276                 current.position = mtc_frame;
277                 current.timestamp = 0;
278                 current.speed = 0;
279                 current.guard2++;
280
281                 break;
282
283         case MTC_Forward:
284                 mtc_frame = 0;
285
286                 current.guard1++;
287                 current.position = mtc_frame;
288                 current.timestamp = 0;
289                 current.speed = 0;
290                 current.guard2++;
291
292                 break;
293
294         case MTC_Backward:
295                 mtc_frame = 0;
296
297                 current.guard1++;
298                 current.position = mtc_frame;
299                 current.timestamp = 0;
300                 current.speed = 0;
301                 current.guard2++;
302
303                 break;
304         }
305 }
306
307 void
308 MTC_Slave::read_current (SafeTime *st) const
309 {
310         int tries = 0;
311
312         do {
313                 if (tries == 10) {
314                         error << _("MTC Slave: atomic read of current time failed, sleeping!") << endmsg;
315                         usleep (20);
316                         tries = 0;
317                 }
318                 *st = current;
319                 tries++;
320
321         } while (st->guard1 != st->guard2);
322 }
323
324 bool
325 MTC_Slave::locked () const
326 {
327         return port->input()->mtc_locked();
328 }
329
330 bool
331 MTC_Slave::ok() const
332 {
333         return true;
334 }
335
336 bool
337 MTC_Slave::speed_and_position (double& speed, nframes64_t& pos)
338 {
339         nframes64_t now = session.engine().frame_time();
340         SafeTime last;
341         nframes_t elapsed;
342
343         read_current (&last);
344
345         if (last.timestamp == 0) {
346                 speed = 0;
347                 pos = last.position;
348                 DEBUG_TRACE (DEBUG::MTC, string_compose ("first call to MTC_Slave::speed_and_position, pos = %1\n", last.position));
349                 return true;
350         }
351
352         /* no timecode for 1/4 second ? conclude that its stopped */
353
354         if (last_inbound_frame && now > last_inbound_frame && now - last_inbound_frame > session.frame_rate() / 4) {
355                 speed = 0;
356                 pos = last.position;
357                 session.request_locate (pos, false);
358                 session.request_transport_speed (0);
359                 update_mtc_status (MIDI::Parser::MTC_Stopped);
360                 reset();
361                 DEBUG_TRACE (DEBUG::MTC, "MTC not seen for 1/4 second - reset\n");
362                 return false;
363         }
364
365         DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC::speed_and_position %1 %2\n", last.speed, last.position));
366
367         if (last.speed == 0.0f) {
368
369                 elapsed = 0;
370
371         } else {
372
373                 /* scale elapsed time by the current MTC speed */
374
375                 if (last.timestamp && (now > last.timestamp)) {
376                         elapsed = (nframes_t) floor (last.speed * (now - last.timestamp));
377                         DEBUG_TRACE (DEBUG_MTC, string_compose ("last timecode received @ %1, now = %2, elapsed frames = %3 w/speed= %4\n",
378                                                                 last.timestamp, now, elapsed, speed);
379                 } else {
380                         elapsed = 0; /* XXX is this right? */
381                 }
382         }
383
384         /* now add the most recent timecode value plus the estimated elapsed interval */
385
386         pos =  elapsed + last.position;
387         speed = last.speed;
388
389         DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC::speed_and_position FINAL %1 %2\n", last.speed, pos));
390
391         return true;
392 }
393
394 ARDOUR::nframes_t
395 MTC_Slave::resolution() const
396 {
397         return (nframes_t) session.frames_per_timecode_frame();
398 }
399
400 void
401 MTC_Slave::reset ()
402 {
403         /* XXX massive thread safety issue here. MTC could
404            be being updated as we call this. but this
405            supposed to be a realtime-safe call.
406         */
407
408         port->input()->reset_mtc_state ();
409
410         last_inbound_frame = 0;
411         current.guard1++;
412         current.position = 0;
413         current.timestamp = 0;
414         current.speed = 0;
415         current.guard2++;
416         accumulator_index = 0;
417         have_first_accumulated_speed = false;
418         qtr_frame_messages_valid_for_time = false;
419 }