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