summaryrefslogtreecommitdiff
path: root/libs/midi++2/mtc.cc
diff options
context:
space:
mode:
authorPaul Davis <paul@linuxaudiosystems.com>2008-06-02 21:41:35 +0000
committerPaul Davis <paul@linuxaudiosystems.com>2008-06-02 21:41:35 +0000
commit449aab3c465bbbf66d221fac3d7ea559f1720357 (patch)
tree6843cc40c88250a132acac701271f1504cd2df04 /libs/midi++2/mtc.cc
parent9c0d7d72d70082a54f823cd44c0ccda5da64bb6f (diff)
rollback to 3428, before the mysterious removal of libs/* at 3431/3432
git-svn-id: svn://localhost/ardour2/branches/3.0@3435 d708f5d6-7413-0410-9779-e7cbd77b26cf
Diffstat (limited to 'libs/midi++2/mtc.cc')
-rw-r--r--libs/midi++2/mtc.cc333
1 files changed, 333 insertions, 0 deletions
diff --git a/libs/midi++2/mtc.cc b/libs/midi++2/mtc.cc
new file mode 100644
index 0000000000..13f5221929
--- /dev/null
+++ b/libs/midi++2/mtc.cc
@@ -0,0 +1,333 @@
+/*
+ Copyright (C) 2004 Paul Barton-Davis
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ $Id$
+*/
+
+#include <cstring>
+#include <cstdlib>
+#include <unistd.h>
+#include <string>
+#include <iostream>
+
+#include <midi++/types.h>
+#include <midi++/parser.h>
+#include <midi++/port.h>
+#include <midi++/mmc.h>
+#include <pbd/transmitter.h>
+
+using namespace std;
+using namespace sigc;
+using namespace MIDI;
+
+bool
+Parser::possible_mtc (byte *sysex_buf, size_t msglen)
+{
+ byte fake_mtc_time[5];
+
+ if (msglen != 10 || sysex_buf[0] != 0xf0 || sysex_buf[1] != 0x7f || sysex_buf[3] != 0x01 || sysex_buf[4] != 0x01) {
+ return false;
+ }
+
+ /* full MTC */
+
+ fake_mtc_time[0] = sysex_buf[8]; // frames
+ fake_mtc_time[1] = sysex_buf[7]; // minutes
+ fake_mtc_time[2] = sysex_buf[6]; // seconds
+ fake_mtc_time[3] = (sysex_buf[5] & 0x1f); // hours
+
+ _mtc_fps = MTC_FPS ((sysex_buf[5] & 0x60) >> 5); // fps
+
+ fake_mtc_time[4] = (byte) _mtc_fps;
+
+ /* wait for first quarter frame, which could indicate forwards
+ or backwards ...
+ */
+
+ reset_mtc_state ();
+
+ /* emit signals */
+
+ mtc (*this, &sysex_buf[1], msglen - 1);
+ mtc_time (fake_mtc_time, true);
+ mtc_status (MTC_Stopped);
+
+ return true;
+}
+
+void
+Parser::reset_mtc_state ()
+{
+ _mtc_forward = false;
+ _mtc_running = MTC_Stopped;
+ _mtc_locked = false;
+ expected_mtc_quarter_frame_code = 0;
+ memset (_mtc_time, 0, sizeof (_mtc_time));
+ memset (_qtr_mtc_time, 0, sizeof (_mtc_time));
+ consecutive_qtr_frame_cnt = 0;
+ last_qtr_frame = 0;
+}
+
+void
+Parser::process_mtc_quarter_frame (byte *msg)
+{
+ int which_quarter_frame = (msg[1] & 0xf0) >> 4;
+
+ /* Is it an expected frame?
+ Remember, the first can be frame 7 or frame 0,
+ depending on the direction of the MTC generator ...
+ */
+
+#if 0
+ cerr << "MTC: (state = " << _mtc_running << ") "
+ << which_quarter_frame << " vs. " << expected_mtc_quarter_frame_code
+ << " consecutive ? " << consecutive_qtr_frame_cnt
+ << endl;
+#endif
+
+ if (_mtc_running == MTC_Stopped) {
+
+ /* we are stopped but are seeing qtr frame messages */
+
+ if (consecutive_qtr_frame_cnt == 0) {
+
+ /* first quarter frame */
+
+ if (which_quarter_frame != 0 && which_quarter_frame != 7) {
+
+ last_qtr_frame = which_quarter_frame;
+ consecutive_qtr_frame_cnt++;
+ }
+
+ // cerr << "first seen qframe = " << (int) last_qtr_frame << endl;
+
+ return;
+
+ } else if (consecutive_qtr_frame_cnt == 1) {
+
+ /* third quarter frame */
+
+ // cerr << "second seen qframe = " << (int) which_quarter_frame << endl;
+
+ if (last_qtr_frame < which_quarter_frame) {
+ _mtc_running = MTC_Forward;
+ } else if (last_qtr_frame > which_quarter_frame) {
+ _mtc_running = MTC_Backward;
+ }
+
+ mtc_status (_mtc_running);
+ }
+
+ switch (_mtc_running) {
+ case MTC_Forward:
+ if (which_quarter_frame == 7) {
+ expected_mtc_quarter_frame_code = 0;
+ } else {
+ expected_mtc_quarter_frame_code = which_quarter_frame + 1;
+ }
+ break;
+
+ case MTC_Backward:
+ if (which_quarter_frame == 0) {
+ expected_mtc_quarter_frame_code = 7;
+
+ } else {
+ expected_mtc_quarter_frame_code = which_quarter_frame - 1;
+ }
+ break;
+
+ case MTC_Stopped:
+ break;
+ }
+
+ } else {
+
+ /* already running */
+
+// for testing bad MIDI connections etc.
+// if ((random() % 500) < 10) {
+
+ if (which_quarter_frame != expected_mtc_quarter_frame_code) {
+
+ consecutive_qtr_frame_cnt = 0;
+
+#ifdef DEBUG_MTC
+ cerr << "MTC: (state = " << _mtc_running << ") "
+ << which_quarter_frame << " vs. " << expected_mtc_quarter_frame_code << endl;
+#endif
+
+ /* tell listener(s) that we skipped. if they return
+ true, just ignore this in terms of it being an error.
+ */
+
+ if (1) { /* mtc_skipped () */
+
+ /* no error, reset next expected frame */
+
+ switch (_mtc_running) {
+ case MTC_Forward:
+ if (which_quarter_frame == 7) {
+ expected_mtc_quarter_frame_code = 0;
+ } else {
+ expected_mtc_quarter_frame_code = which_quarter_frame + 1;
+ }
+ break;
+
+ case MTC_Backward:
+ if (which_quarter_frame == 0) {
+ expected_mtc_quarter_frame_code = 7;
+
+ } else {
+ expected_mtc_quarter_frame_code = which_quarter_frame - 1;
+ }
+ break;
+
+ case MTC_Stopped:
+ break;
+ }
+
+#ifdef DEBUG_MTC
+ cerr << "SKIPPED, next expected = " << expected_mtc_quarter_frame_code << endl;
+#endif
+ return;
+ }
+
+ /* go back to waiting for the first frame */
+
+ expected_mtc_quarter_frame_code = 0;
+ memset (_qtr_mtc_time, 0, sizeof (_qtr_mtc_time));
+
+ _mtc_running = MTC_Stopped;
+ _mtc_locked = false;
+ mtc_status (MTC_Stopped);
+
+ return;
+
+ } else {
+
+ /* received qtr frame matched expected */
+ consecutive_qtr_frame_cnt++;
+
+ }
+ }
+
+ /* time code is looking good */
+
+ switch (which_quarter_frame) {
+ case 0: // frames LS nibble
+ _qtr_mtc_time[0] |= msg[1] & 0xf;
+ break;
+
+ case 1: // frames MS nibble
+ _qtr_mtc_time[0] |= (msg[1] & 0xf)<<4;
+ break;
+
+ case 2: // seconds LS nibble
+ _qtr_mtc_time[1] |= msg[1] & 0xf;
+ break;
+
+ case 3: // seconds MS nibble
+ _qtr_mtc_time[1] |= (msg[1] & 0xf)<<4;
+ break;
+
+ case 4: // minutes LS nibble
+ _qtr_mtc_time[2] |= msg[1] & 0xf;
+ break;
+
+ case 5: // minutes MS nibble
+ _qtr_mtc_time[2] |= (msg[1] & 0xf)<<4;
+ break;
+
+ case 6: // hours LS nibble
+ _qtr_mtc_time[3] |= msg[1] & 0xf;
+ break;
+
+ case 7:
+
+ /* last quarter frame msg has the MS bit of
+ the hour in bit 0, and the SMPTE FPS type
+ in bits 5 and 6
+ */
+
+ _qtr_mtc_time[3] |= ((msg[1] & 0x1) << 4);
+ _mtc_fps = MTC_FPS ((msg[1] & 0x6) >> 1);
+ _qtr_mtc_time[4] = _mtc_fps;
+ break;
+
+ default:
+ /*NOTREACHED*/
+ break;
+
+ }
+
+ mtc_qtr (*this); /* EMIT_SIGNAL */
+
+ // mtc (*this, &msg[1], msglen - 1);
+
+ switch (_mtc_running) {
+ case MTC_Forward:
+ if ((which_quarter_frame == 7)) {
+
+ /* we've reached the final of 8 quarter frame messages.
+ store the time, reset the pending time holder,
+ and signal anyone who wants to know the time.
+ */
+
+ if (consecutive_qtr_frame_cnt >= 8) {
+ memcpy (_mtc_time, _qtr_mtc_time, sizeof (_mtc_time));
+ memset (_qtr_mtc_time, 0, sizeof (_qtr_mtc_time));
+ if (!_mtc_locked) {
+ _mtc_locked = true;
+ }
+ mtc_time (_mtc_time, false);
+ }
+ expected_mtc_quarter_frame_code = 0;
+
+ } else {
+ expected_mtc_quarter_frame_code = which_quarter_frame + 1;
+ }
+ break;
+
+ case MTC_Backward:
+ if (which_quarter_frame == 0) {
+
+ /* we've reached the final of 8 quarter frame messages.
+ store the time, reset the pending time holder,
+ and signal anyone who wants to know the time.
+ */
+
+ if (consecutive_qtr_frame_cnt >= 8) {
+ memcpy (_mtc_time, _qtr_mtc_time, sizeof (_mtc_time));
+ memset (_qtr_mtc_time, 0, sizeof (_qtr_mtc_time));
+ if (!_mtc_locked) {
+ _mtc_locked = true;
+ }
+ mtc_time (_mtc_time, false);
+ }
+
+ expected_mtc_quarter_frame_code = 7;
+
+ } else {
+ expected_mtc_quarter_frame_code = which_quarter_frame - 1;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+}