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