Logo Search packages:      
Sourcecode: ardour version File versions  Download package

mtc.cc

/*
    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: mtc.cc,v 1.8 2005/04/09 13:38:14 pauld Exp $
*/

#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[4];

      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
      
      /* 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);
            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;
      }

}

Generated by  Doxygen 1.6.0   Back to index