SVG of thorsten's editor track/bus list icons
[ardour2.git] / libs / midi++2 / mtc.cc
blobd1bb7c9bad673c814c3f5ea1098418b5e7e7b629
1 /*
2 Copyright (C) 2004 Paul Barton-Davis
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.
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.
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.
18 $Id$
21 #include <cstdlib>
22 #include <unistd.h>
23 #include <cstring>
24 #include <iostream>
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"
32 using namespace std;
33 using namespace sigc;
34 using namespace MIDI;
36 #undef DEBUG_MTC
38 bool
39 Parser::possible_mtc (byte *sysex_buf, size_t msglen)
41 byte fake_mtc_time[5];
43 if (msglen != 10 || sysex_buf[0] != 0xf0 || sysex_buf[1] != 0x7f || sysex_buf[3] != 0x01 || sysex_buf[4] != 0x01) {
44 return false;
47 /* full MTC */
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
54 _mtc_fps = MTC_FPS ((sysex_buf[5] & 0x60) >> 5); // fps
55 fake_mtc_time[4] = (byte) _mtc_fps;
57 /* wait for first quarter frame, which could indicate forwards
58 or backwards ...
61 reset_mtc_state ();
63 /* emit signals */
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);
72 return true;
75 void
76 Parser::reset_mtc_state ()
78 #ifdef DEBUG_MTC
79 cerr << "MTC state reset" << endl;
80 #endif
81 /* MUST REMAIN RT-SAFE */
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;
93 void
94 Parser::process_mtc_quarter_frame (byte *msg)
96 int which_quarter_frame = (msg[1] & 0xf0) >> 4;
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 ...
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
110 if (_mtc_running == MTC_Stopped) {
112 /* we are stopped but are seeing qtr frame messages */
114 if (consecutive_qtr_frame_cnt == 0) {
116 /* first quarter frame */
118 if (which_quarter_frame != 0 && which_quarter_frame != 7) {
120 last_qtr_frame = which_quarter_frame;
121 consecutive_qtr_frame_cnt++;
124 // cerr << "first seen qframe = " << (int) last_qtr_frame << endl;
126 return;
128 } else if (consecutive_qtr_frame_cnt == 1) {
130 /* third quarter frame */
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;
140 #ifdef DEBUG_MTC
141 cerr << "Send MTC status as " << _mtc_running << endl;
142 #endif
143 mtc_status (_mtc_running);
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;
153 break;
155 case MTC_Backward:
156 if (which_quarter_frame == 0) {
157 expected_mtc_quarter_frame_code = 7;
159 } else {
160 expected_mtc_quarter_frame_code = which_quarter_frame - 1;
162 break;
164 case MTC_Stopped:
165 break;
168 } else {
170 /* already running */
172 // for testing bad MIDI connections etc.
173 // if ((random() % 500) < 10) {
175 if (which_quarter_frame != expected_mtc_quarter_frame_code) {
177 consecutive_qtr_frame_cnt = 0;
179 #ifdef DEBUG_MTC
180 cerr << "MTC: (state = " << _mtc_running << ") "
181 << which_quarter_frame << " vs. " << expected_mtc_quarter_frame_code << endl;
182 #endif
184 /* tell listener(s) that we skipped. if they return
185 true, just ignore this in terms of it being an error.
188 boost::optional<bool> res = mtc_skipped ();
190 if (res.get_value_or (false)) {
192 /* no error, reset next expected frame */
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;
201 break;
203 case MTC_Backward:
204 if (which_quarter_frame == 0) {
205 expected_mtc_quarter_frame_code = 7;
207 } else {
208 expected_mtc_quarter_frame_code = which_quarter_frame - 1;
210 break;
212 case MTC_Stopped:
213 break;
216 #ifdef DEBUG_MTC
217 cerr << "SKIPPED, next expected = " << expected_mtc_quarter_frame_code << endl;
218 #endif
219 return;
222 /* skip counts as an error ... go back to waiting for the first frame */
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);
230 return;
232 } else {
234 /* received qtr frame matched expected */
235 consecutive_qtr_frame_cnt++;
240 /* time code is looking good */
242 #ifdef DEBUG_MTC
243 // cerr << "for quarter frame " << which_quarter_frame << " byte = " << hex << (int) msg[1] << dec << endl;
244 #endif
246 switch (which_quarter_frame) {
247 case 0: // frames LS nibble
248 _qtr_mtc_time[0] |= msg[1] & 0xf;
249 break;
251 case 1: // frames MS nibble
252 _qtr_mtc_time[0] |= (msg[1] & 0xf)<<4;
253 break;
255 case 2: // seconds LS nibble
256 _qtr_mtc_time[1] |= msg[1] & 0xf;
257 break;
259 case 3: // seconds MS nibble
260 _qtr_mtc_time[1] |= (msg[1] & 0xf)<<4;
261 break;
263 case 4: // minutes LS nibble
264 _qtr_mtc_time[2] |= msg[1] & 0xf;
265 break;
267 case 5: // minutes MS nibble
268 _qtr_mtc_time[2] |= (msg[1] & 0xf)<<4;
269 break;
271 case 6: // hours LS nibble
272 _qtr_mtc_time[3] |= msg[1] & 0xf;
273 break;
275 case 7:
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
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;
287 default:
288 /*NOTREACHED*/
289 break;
293 #ifdef DEBUG_MTC
294 cerr << "Emit MTC Qtr\n";
295 #endif
297 mtc_qtr (*this, which_quarter_frame, _timestamp); /* EMIT_SIGNAL */
299 // mtc (*this, &msg[1], msglen - 1);
301 switch (_mtc_running) {
302 case MTC_Forward:
303 if ((which_quarter_frame == 7)) {
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.
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;
317 mtc_time (_mtc_time, false, _timestamp);
319 expected_mtc_quarter_frame_code = 0;
321 } else {
322 expected_mtc_quarter_frame_code = which_quarter_frame + 1;
324 break;
326 case MTC_Backward:
327 if (which_quarter_frame == 0) {
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.
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;
340 mtc_time (_mtc_time, false, _timestamp);
343 expected_mtc_quarter_frame_code = 7;
345 } else {
346 expected_mtc_quarter_frame_code = which_quarter_frame - 1;
348 break;
350 default:
351 break;