NOOP, remove trailing tabs/whitespace.
[ardour.git] / libs / midi++2 / mtc.cc
1 /*
2     Copyright (C) 2004 Paul Barton-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     $Id$
19 */
20
21 #include <cstdlib>
22 #include <unistd.h>
23 #include <cstring>
24 #include <iostream>
25
26 #include "midi++/types.h"
27 #include "midi++/parser.h"
28 #include "midi++/port.h"
29 #include "midi++/mmc.h"
30 #include "pbd/transmitter.h"
31
32 using namespace std;
33 using namespace sigc;
34 using namespace MIDI;
35
36 #undef DEBUG_MTC
37
38 bool
39 Parser::possible_mtc (MIDI::byte *sysex_buf, size_t msglen)
40 {
41         byte fake_mtc_time[5];
42
43         if (msglen != 10 || sysex_buf[0] != 0xf0 || sysex_buf[1] != 0x7f || sysex_buf[3] != 0x01 || sysex_buf[4] != 0x01) {
44                 return false;
45         }
46
47         /* full MTC */
48
49         fake_mtc_time[0] = sysex_buf[8]; // frames
50         fake_mtc_time[1] = sysex_buf[7]; // minutes
51         fake_mtc_time[2] = sysex_buf[6]; // seconds
52         fake_mtc_time[3] = (sysex_buf[5] & 0x1f); // hours
53
54         _mtc_fps = MTC_FPS ((sysex_buf[5] & 0x60) >> 5); // fps
55         fake_mtc_time[4] = (byte) _mtc_fps;
56
57         /* wait for first quarter frame, which could indicate forwards
58            or backwards ...
59         */
60
61         reset_mtc_state ();
62
63         /* emit signals */
64
65         mtc (*this, &sysex_buf[1], msglen - 1);
66         mtc_time (fake_mtc_time, true, _timestamp);
67 #ifdef DEBUG_MTC
68         cerr << "New full-MTC message marks state stopped" << endl;
69 #endif
70         mtc_status (MTC_Stopped);
71
72         return true;
73 }
74
75 void
76 Parser::reset_mtc_state ()
77 {
78 #ifdef DEBUG_MTC
79         cerr << "MTC state reset" << endl;
80 #endif
81         /* MUST REMAIN RT-SAFE */
82
83         _mtc_forward = false;
84         _mtc_running = MTC_Stopped;
85         _mtc_locked = false;
86         expected_mtc_quarter_frame_code = 0;
87         memset (_mtc_time, 0, sizeof (_mtc_time));
88         memset (_qtr_mtc_time, 0, sizeof (_mtc_time));
89         consecutive_qtr_frame_cnt = 0;
90         last_qtr_frame = 0;
91 }
92
93 void
94 Parser::process_mtc_quarter_frame (MIDI::byte *msg)
95 {
96         int which_quarter_frame = (msg[1] & 0xf0) >> 4;
97
98         /* Is it an expected frame?
99            Remember, the first can be frame 7 or frame 0,
100            depending on the direction of the MTC generator ...
101         */
102
103 #ifdef DEBUG_MTC
104          cerr << "MTC: (state = " << _mtc_running << ") "
105               << which_quarter_frame << " vs. " << expected_mtc_quarter_frame_code
106               << " consecutive ? " << consecutive_qtr_frame_cnt
107               << endl;
108 #endif
109
110         if (_mtc_running == MTC_Stopped) {
111
112                 /* we are stopped but are seeing qtr frame messages */
113
114                 if (consecutive_qtr_frame_cnt == 0) {
115
116                         /* first quarter frame */
117
118                         if (which_quarter_frame != 0 && which_quarter_frame != 7) {
119
120                                 last_qtr_frame = which_quarter_frame;
121                                 consecutive_qtr_frame_cnt++;
122                         }
123
124                         // cerr << "first seen qframe = " << (int) last_qtr_frame << endl;
125
126                         return;
127
128                 } else if (consecutive_qtr_frame_cnt == 1) {
129
130                         /* third quarter frame */
131
132 #ifdef DEBUG_MTC
133                         cerr << "second seen qframe = " << (int) which_quarter_frame << endl;
134 #endif
135                         if (last_qtr_frame < which_quarter_frame) {
136                                 _mtc_running = MTC_Forward;
137                         } else if (last_qtr_frame > which_quarter_frame) {
138                                 _mtc_running = MTC_Backward;
139                         }
140 #ifdef DEBUG_MTC
141                         cerr << "Send MTC status as " << _mtc_running << endl;
142 #endif
143                         mtc_status (_mtc_running);
144                 }
145
146                 switch (_mtc_running) {
147                 case MTC_Forward:
148                         if (which_quarter_frame == 7) {
149                                 expected_mtc_quarter_frame_code = 0;
150                         } else {
151                                 expected_mtc_quarter_frame_code = which_quarter_frame + 1;
152                         }
153                         break;
154
155                 case MTC_Backward:
156                         if (which_quarter_frame == 0) {
157                                 expected_mtc_quarter_frame_code = 7;
158
159                         } else {
160                                 expected_mtc_quarter_frame_code = which_quarter_frame - 1;
161                         }
162                         break;
163
164                 case MTC_Stopped:
165                         break;
166                 }
167
168         } else {
169
170                 /* already running */
171
172 // for testing bad MIDI connections etc.
173 //              if ((random() % 500) < 10) {
174
175                 if (which_quarter_frame != expected_mtc_quarter_frame_code) {
176
177                         consecutive_qtr_frame_cnt = 0;
178
179 #ifdef DEBUG_MTC
180                         cerr << "MTC: (state = " << _mtc_running << ") "
181                              << which_quarter_frame << " vs. " << expected_mtc_quarter_frame_code << endl;
182 #endif
183
184                         /* tell listener(s) that we skipped. if they return
185                            true, just ignore this in terms of it being an error.
186                         */
187
188                         boost::optional<bool> res = mtc_skipped ();
189
190                         if (res.get_value_or (false)) {
191
192                                 /* no error, reset next expected frame */
193
194                                 switch (_mtc_running) {
195                                 case MTC_Forward:
196                                         if (which_quarter_frame == 7) {
197                                                 expected_mtc_quarter_frame_code = 0;
198                                         } else {
199                                                 expected_mtc_quarter_frame_code = which_quarter_frame + 1;
200                                         }
201                                         break;
202
203                                 case MTC_Backward:
204                                         if (which_quarter_frame == 0) {
205                                                 expected_mtc_quarter_frame_code = 7;
206
207                                         } else {
208                                                 expected_mtc_quarter_frame_code = which_quarter_frame - 1;
209                                         }
210                                         break;
211
212                                 case MTC_Stopped:
213                                         break;
214                                 }
215
216 #ifdef DEBUG_MTC
217                                 cerr << "SKIPPED, next expected = " << expected_mtc_quarter_frame_code << endl;
218 #endif
219                                 return;
220                         }
221
222                         /* skip counts as an error ... go back to waiting for the first frame */
223
224 #ifdef DEBUG_MTC
225                         cerr << "Skipped MTC qtr frame, return to stopped state" << endl;
226 #endif
227                         reset_mtc_state ();
228                         mtc_status (MTC_Stopped);
229
230                         return;
231
232                 } else {
233
234                         /* received qtr frame matched expected */
235                         consecutive_qtr_frame_cnt++;
236
237                 }
238         }
239
240         /* time code is looking good */
241
242 #ifdef DEBUG_MTC
243         cerr << "for quarter frame " << which_quarter_frame << " byte = " << hex << (int) msg[1] << dec << endl;
244 #endif
245
246         switch (which_quarter_frame) {
247         case 0: // frames LS nibble
248                 _qtr_mtc_time[0] |= msg[1] & 0xf;
249                 break;
250
251         case 1:  // frames MS nibble
252                 _qtr_mtc_time[0] |= (msg[1] & 0xf)<<4;
253                 break;
254
255         case 2: // seconds LS nibble
256                 _qtr_mtc_time[1] |= msg[1] & 0xf;
257                 break;
258
259         case 3: // seconds MS nibble
260                 _qtr_mtc_time[1] |= (msg[1] & 0xf)<<4;
261                 break;
262
263         case 4: // minutes LS nibble
264                 _qtr_mtc_time[2] |= msg[1] & 0xf;
265                 break;
266
267         case 5: // minutes MS nibble
268                 _qtr_mtc_time[2] |= (msg[1] & 0xf)<<4;
269                 break;
270
271         case 6: // hours LS nibble
272                 _qtr_mtc_time[3] |= msg[1] & 0xf;
273                 break;
274
275         case 7:
276
277                 /* last quarter frame msg has the MS bit of
278                    the hour in bit 0, and the SMPTE FPS type
279                    in bits 5 and 6
280                 */
281
282                 _qtr_mtc_time[3] |= ((msg[1] & 0x1) << 4);
283                 _mtc_fps = MTC_FPS ((msg[1] & 0x6) >> 1);
284                 _qtr_mtc_time[4] = _mtc_fps;
285                 break;
286
287         default:
288                 abort(); /*NOTREACHED*/
289                 break;
290
291         }
292
293 #ifdef DEBUG_MTC
294         cerr << "Emit MTC Qtr\n";
295 #endif
296
297         mtc_qtr (*this, which_quarter_frame, _timestamp); /* EMIT_SIGNAL */
298
299         // mtc (*this, &msg[1], msglen - 1);
300
301         switch (_mtc_running) {
302         case MTC_Forward:
303                 if (which_quarter_frame == 7) {
304
305                         /* we've reached the final of 8 quarter frame messages.
306                            store the time, reset the pending time holder,
307                            and signal anyone who wants to know the time.
308                         */
309
310                         if (consecutive_qtr_frame_cnt >= 8) {
311                                 memcpy (_mtc_time, _qtr_mtc_time, sizeof (_mtc_time));
312                                 memset (_qtr_mtc_time, 0, sizeof (_qtr_mtc_time));
313                                 if (!_mtc_locked) {
314                                         _mtc_locked = true;
315                                 }
316
317                                 mtc_time (_mtc_time, false, _timestamp);
318                         }
319                         expected_mtc_quarter_frame_code = 0;
320
321                 } else {
322                         expected_mtc_quarter_frame_code = which_quarter_frame + 1;
323                 }
324                 break;
325
326         case MTC_Backward:
327                 if (which_quarter_frame == 0) {
328
329                         /* we've reached the final of 8 quarter frame messages.
330                            store the time, reset the pending time holder,
331                            and signal anyone who wants to know the time.
332                         */
333
334                         if (consecutive_qtr_frame_cnt >= 8) {
335                                 memcpy (_mtc_time, _qtr_mtc_time, sizeof (_mtc_time));
336                                 memset (_qtr_mtc_time, 0, sizeof (_qtr_mtc_time));
337                                 if (!_mtc_locked) {
338                                         _mtc_locked = true;
339                                 }
340                                 mtc_time (_mtc_time, false, _timestamp);
341                         }
342
343                         expected_mtc_quarter_frame_code = 7;
344
345                 } else {
346                         expected_mtc_quarter_frame_code = which_quarter_frame - 1;
347                 }
348                 break;
349
350         default:
351                 break;
352         }
353
354 }