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