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