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