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