diff options
| -rw-r--r-- | muse/ChangeLog | 7 | ||||
| -rw-r--r-- | muse/muse/audio.cpp | 44 | ||||
| -rw-r--r-- | muse/muse/driver/alsamidi.cpp | 5 | ||||
| -rw-r--r-- | muse/muse/midi.cpp | 24 | ||||
| -rw-r--r-- | muse/muse/midi.h | 11 | ||||
| -rw-r--r-- | muse/muse/mididev.cpp | 75 | ||||
| -rw-r--r-- | muse/muse/midiport.cpp | 61 | ||||
| -rw-r--r-- | muse/muse/midiport.h | 5 | ||||
| -rw-r--r-- | muse/muse/midiseq.cpp | 1 | ||||
| -rw-r--r-- | muse/muse/midiseq.h | 11 | ||||
| -rw-r--r-- | muse/muse/mtc.cpp | 21 | ||||
| -rw-r--r-- | muse/muse/mtc.h | 6 | ||||
| -rw-r--r-- | muse/muse/sync.cpp | 369 | ||||
| -rw-r--r-- | muse/muse/sync.h | 20 | ||||
| -rw-r--r-- | muse/muse/widgets/midisyncimpl.cpp | 313 | ||||
| -rw-r--r-- | muse/muse/widgets/midisyncimpl.h | 4 | 
16 files changed, 842 insertions, 135 deletions
| diff --git a/muse/ChangeLog b/muse/ChangeLog index 4b5376ca..b555dc38 100644 --- a/muse/ChangeLog +++ b/muse/ChangeLog @@ -1,3 +1,10 @@ +23.01.2010 +      * Fixed: External midi sync in: MusE transport not rewinding upon reception of start. (T356) +      * Added: Midi sync: MusE now transmits and receives some MMC commands, and displays some MTC and SMTPE info. (T356) +        - No transmit MTC or receive MTC syncing yet, just transport control stuff. +        - Tested OK with Rosegarden and Ardour, but they do not seem to have an option to sync to the input midi clock,  +           only MTC or internally. Must test when MTC output added to MusE.  +      * Improved: Midi sync editor window: Shows MMC and MTC activity and works with them now. (T356)  21.01.2010        * Fixed: First tests: External midi sync in works now! Should be rock solid no matter what is thrown at it. (T356)          - All changes are labeled "p3.3.25" diff --git a/muse/muse/audio.cpp b/muse/muse/audio.cpp index aa5cebdd..e8b38904 100644 --- a/muse/muse/audio.cpp +++ b/muse/muse/audio.cpp @@ -36,11 +36,11 @@ Audio* audio;  AudioDevice* audioDevice;   // current audio device in use  // p3.3.25 -extern unsigned int midiExtSyncTicks; +extern unsigned int volatile midiExtSyncTicks; -static const unsigned char mmcDeferredPlayMsg[] = { 0x7f, 0x7f, 0x06, 0x03 }; -static const unsigned char mmcStopMsg[] =         { 0x7f, 0x7f, 0x06, 0x01 }; +//static const unsigned char mmcDeferredPlayMsg[] = { 0x7f, 0x7f, 0x06, 0x03 }; +//static const unsigned char mmcStopMsg[] =         { 0x7f, 0x7f, 0x06, 0x01 };  const char* seqMsgList[] = {        "SEQM_ADD_TRACK", "SEQM_REMOVE_TRACK", "SEQM_CHANGE_TRACK", "SEQM_MOVE_TRACK", @@ -234,10 +234,6 @@ bool Audio::sync(int jackState, unsigned frame)  // Changed by Tim. p3.3.24  /*       -      // Added by Tim. p3.3.20 -      if(debugMsg) -        printf("Audio::sync state %s jackState %s frame %d\n", audioStates[state], audioStates[jackState], frame); -              bool done = true;        if (state == LOOP1)               state = LOOP2; @@ -252,10 +248,6 @@ bool Audio::sync(int jackState, unsigned frame)                    done = audioPrefetch->seekDone();              } -      // Added by Tim. p3.3.20 -      //if(debugMsg) -      //  printf("Audio::sync done:%d state %s\n", done, audioStates[state]); -              return done;  */              bool done = true; @@ -974,7 +966,8 @@ void Audio::startRolling()          //if(genMMC && si.MMCOut())          if(si.MMCOut()) -          mp->sendSysex(mmcDeferredPlayMsg, sizeof(mmcDeferredPlayMsg)); +          //mp->sendSysex(mmcDeferredPlayMsg, sizeof(mmcDeferredPlayMsg)); +          mp->sendMMCDeferredPlay();          //if(genMCSync && si.MCOut())          if(si.MCOut()) @@ -1093,6 +1086,8 @@ void Audio::startRolling()                    }                }            } +      +     //tempomap.clearExtTempoList();            }  //--------------------------------------------------------- @@ -1170,20 +1165,23 @@ void Audio::stopRolling()          //if(genMMC && si.MMCOut())          if(si.MMCOut())          { -          unsigned char mmcPos[] = { -                0x7f, 0x7f, 0x06, 0x44, 0x06, 0x01, -                0, 0, 0, 0, 0 -                }; +          //unsigned char mmcPos[] = { +          //      0x7f, 0x7f, 0x06, 0x44, 0x06, 0x01, +          //      0, 0, 0, 0, 0 +          //      };            int frame = tempomap.tick2frame(curTickPos);            MTC mtc(double(frame) / double(sampleRate)); -          mmcPos[6] = mtc.h() | (mtcType << 5); -          mmcPos[7] = mtc.m(); -          mmcPos[8] = mtc.s(); -          mmcPos[9] = mtc.f(); -          mmcPos[10] = mtc.sf(); +          //mmcPos[6] = mtc.h() | (mtcType << 5); +          //mmcPos[7] = mtc.m(); +          //mmcPos[8] = mtc.s(); +          //mmcPos[9] = mtc.f(); +          //mmcPos[10] = mtc.sf(); -          mp->sendSysex(mmcStopMsg, sizeof(mmcStopMsg)); -          mp->sendSysex(mmcPos, sizeof(mmcPos)); +          //mp->sendSysex(mmcStopMsg, sizeof(mmcStopMsg)); +          mp->sendMMCStop(); +          //mp->sendSysex(mmcPos, sizeof(mmcPos)); +          mp->sendMMCLocate(mtc.h() | (mtcType << 5),  +                            mtc.m(), mtc.s(), mtc.f(), mtc.sf());          }          //if(genMCSync && si.MCOut()) // Midi Clock diff --git a/muse/muse/driver/alsamidi.cpp b/muse/muse/driver/alsamidi.cpp index b3aeddd3..f6483a6b 100644 --- a/muse/muse/driver/alsamidi.cpp +++ b/muse/muse/driver/alsamidi.cpp @@ -775,9 +775,10 @@ void alsaProcessMidiInput()              if(event.type())              {                mdev->recordEvent(event); -              if(ev->type != SND_SEQ_EVENT_SYSEX) +              // p3.3.26 1/23/10 Moved to MidiDevice now. Anticipating Jack midi support, so don't make it ALSA specific. Tim. +              //if(ev->type != SND_SEQ_EVENT_SYSEX)                  // Trigger general activity indicator detector. Sysex has no channel, don't trigger. -                midiPorts[curPort].syncInfo().trigActDetect(event.channel()); +              //  midiPorts[curPort].syncInfo().trigActDetect(event.channel());              }              snd_seq_free_event(ev); diff --git a/muse/muse/midi.cpp b/muse/muse/midi.cpp index 60b63179..d330f51e 100644 --- a/muse/muse/midi.cpp +++ b/muse/muse/midi.cpp @@ -32,12 +32,24 @@  extern void dump(const unsigned char* p, int n); -const unsigned char gmOnMsg[] = { 0x7e, 0x7f, 0x09, 0x01 }; -const unsigned char gsOnMsg[] = { 0x41, 0x10, 0x42, 0x12, 0x40, 0x00, 0x7f, 0x00, 0x41 }; -const unsigned char xgOnMsg[] = { 0x43, 0x10, 0x4c, 0x00, 0x00, 0x7e, 0x00 }; -const unsigned int  gmOnMsgLen = sizeof(gmOnMsg); -const unsigned int  gsOnMsgLen = sizeof(gsOnMsg); -const unsigned int  xgOnMsgLen = sizeof(xgOnMsg); +const unsigned char gmOnMsg[]   = { 0x7e, 0x7f, 0x09, 0x01 }; +const unsigned char gsOnMsg[]   = { 0x41, 0x10, 0x42, 0x12, 0x40, 0x00, 0x7f, 0x00, 0x41 }; +const unsigned char gsOnMsg2[]  = { 0x41, 0x10, 0x42, 0x12, 0x40, 0x01, 0x33, 0x50, 0x3c }; +const unsigned char gsOnMsg3[]  = { 0x41, 0x10, 0x42, 0x12, 0x40, 0x01, 0x34, 0x50, 0x3b }; +const unsigned char xgOnMsg[]   = { 0x43, 0x10, 0x4c, 0x00, 0x00, 0x7e, 0x00 }; +const unsigned int  gmOnMsgLen  = sizeof(gmOnMsg); +const unsigned int  gsOnMsgLen  = sizeof(gsOnMsg); +const unsigned int  gsOnMsg2Len = sizeof(gsOnMsg2); +const unsigned int  gsOnMsg3Len = sizeof(gsOnMsg3); +const unsigned int  xgOnMsgLen  = sizeof(xgOnMsg); + +const unsigned char mmcDeferredPlayMsg[] = { 0x7f, 0x7f, 0x06, 0x03 }; +const unsigned char mmcStopMsg[] =         { 0x7f, 0x7f, 0x06, 0x01 }; +const unsigned char mmcLocateMsg[] =       { 0x7f, 0x7f, 0x06, 0x44, 0x06, 0x01, 0, 0, 0, 0, 0 }; + +const unsigned int  mmcDeferredPlayMsgLen = sizeof(mmcDeferredPlayMsg); +const unsigned int  mmcStopMsgLen = sizeof(mmcStopMsg); +const unsigned int  mmcLocateMsgLen = sizeof(mmcLocateMsg);  #define CALC_TICK(the_tick) lrintf((float(the_tick) * float(config.division) + float(div/2)) / float(div));  /*--------------------------------------------------------- diff --git a/muse/muse/midi.h b/muse/muse/midi.h index d9bc1fc5..ee4c6291 100644 --- a/muse/muse/midi.h +++ b/muse/muse/midi.h @@ -34,12 +34,23 @@ enum {  #define ME_TIMESIG      0x58  extern const unsigned char gmOnMsg[]; +  extern const unsigned char gsOnMsg[]; +extern const unsigned char gsOnMsg2[]; +extern const unsigned char gsOnMsg3[];  extern const unsigned char xgOnMsg[]; +extern const unsigned char mmcDeferredPlayMsg[]; +extern const unsigned char mmcStopMsg[]; +extern const unsigned char mmcLocateMsg[];  extern const unsigned int gmOnMsgLen;  extern const unsigned int gsOnMsgLen; +extern const unsigned int gsOnMsg2Len; +extern const unsigned int gsOnMsg3Len;  extern const unsigned int xgOnMsgLen; +extern const unsigned int mmcDeferredPlayMsgLen; +extern const unsigned int mmcStopMsgLen; +extern const unsigned int mmcLocateMsgLen;  QString nameSysex(unsigned int len, const unsigned char* buf);  QString midiMetaName(int); diff --git a/muse/muse/mididev.cpp b/muse/muse/mididev.cpp index 6a649798..aec9a51d 100644 --- a/muse/muse/mididev.cpp +++ b/muse/muse/mididev.cpp @@ -162,36 +162,53 @@ void MidiDevice::recordEvent(MidiRecordEvent& event)              printf("MidiInput: ");              event.dump();              } -#if 0 -      int typ = event.type(); - -      //--------------------------------------------------- -      // filter some SYSEX events -      //--------------------------------------------------- - -      if (typ == ME_SYSEX) { -            const unsigned char* p = event.data(); -            int n = event.len(); -            if (n >= 4) { -                  if ((p[0] == 0x7f) -                     && ((p[1] == 0x7f) || (p[1] == rxDeviceId))) { -                        if (p[2] == 0x06) { -                              mmcInput(p, n); -                              return; -                              } -                        if (p[2] == 0x01) { -                              mtcInputFull(p, n); -                              return; -                              } -                        } -                  else if (p[0] == 0x7e) { -                        nonRealtimeSystemSysex(p, n); -                        return; -                        } -                  } -            } -#endif +      if(_port != -1) +      { +        int idin = midiPorts[_port].syncInfo().idIn(); +         +// p3.3.26 1/23/10 Section was disabled, enabled by Tim. +//#if 0 +        int typ = event.type(); +   +        //--------------------------------------------------- +        // filter some SYSEX events +        //--------------------------------------------------- +   +        if (typ == ME_SYSEX) { +              const unsigned char* p = event.data(); +              int n = event.len(); +              if (n >= 4) { +                    if ((p[0] == 0x7f) +                      //&& ((p[1] == 0x7f) || (p[1] == rxDeviceId))) { +                      && ((p[1] == 0x7f) || (idin == 0x7f) || (p[1] == idin))) { +                          if (p[2] == 0x06) { +                                //mmcInput(p, n); +                                midiSeq->mmcInput(_port, p, n); +                                return; +                                } +                          if (p[2] == 0x01) { +                                //mtcInputFull(p, n); +                                midiSeq->mtcInputFull(_port, p, n); +                                return; +                                } +                          } +                    else if (p[0] == 0x7e) { +                          //nonRealtimeSystemSysex(p, n); +                          midiSeq->nonRealtimeSystemSysex(_port, p, n); +                          return; +                          } +                    } +              } +          else     +            // p3.3.26 1/23/10 Moved here from alsaProcessMidiInput(). Anticipating Jack midi support, so don't make it ALSA specific. Tim.  +            // Trigger general activity indicator detector. Sysex has no channel, don't trigger. +            midiPorts[_port].syncInfo().trigActDetect(event.channel()); +               +//#endif + +      } +              //        //  process midi event input filtering and        //    transformation diff --git a/muse/muse/midiport.cpp b/muse/muse/midiport.cpp index 568fa68d..177e957c 100644 --- a/muse/muse/midiport.cpp +++ b/muse/muse/midiport.cpp @@ -433,11 +433,12 @@ void MidiPort::sendGmOn()  void MidiPort::sendGsOn()        { -      static unsigned char data2[] = { 0x41, 0x10, 0x42, 0x12, 0x40, 0x01, 0x33, 0x50, 0x3c }; -      static unsigned char data3[] = { 0x41, 0x10, 0x42, 0x12, 0x40, 0x01, 0x34, 0x50, 0x3b }; - -      sendSysex(data2, sizeof(data2)); -      sendSysex(data3, sizeof(data3)); +      //static unsigned char data2[] = { 0x41, 0x10, 0x42, 0x12, 0x40, 0x01, 0x33, 0x50, 0x3c }; +      //static unsigned char data3[] = { 0x41, 0x10, 0x42, 0x12, 0x40, 0x01, 0x34, 0x50, 0x3b }; +      //sendSysex(data2, sizeof(data2)); +      //sendSysex(data3, sizeof(data3)); +      sendSysex(gsOnMsg2, gsOnMsg2Len); +      sendSysex(gsOnMsg3, gsOnMsg3Len);        }  //--------------------------------------------------------- @@ -465,6 +466,56 @@ void MidiPort::sendSysex(const unsigned char* p, int n)        }  //--------------------------------------------------------- +//   sendMMCLocate +//--------------------------------------------------------- + +void MidiPort::sendMMCLocate(unsigned char ht, unsigned char m, unsigned char s, unsigned char f, unsigned char sf, int devid) +{ +  unsigned char msg[mmcLocateMsgLen]; +  memcpy(msg, mmcLocateMsg, mmcLocateMsgLen); +  if(devid != -1) +    msg[1]  = devid; +  else +    msg[1]  = _syncInfo.idOut(); +  msg[6]    = ht; +  msg[7]    = m; +  msg[8]    = s; +  msg[9]    = f; +  msg[10]   = sf; +  sendSysex(msg, mmcLocateMsgLen); +} + +//--------------------------------------------------------- +//   sendMMCStop +//--------------------------------------------------------- + +void MidiPort::sendMMCStop(int devid) +{ +  unsigned char msg[mmcStopMsgLen]; +  memcpy(msg, mmcStopMsg, mmcStopMsgLen); +  if(devid != -1) +    msg[1] = devid; +  else +    msg[1] = _syncInfo.idOut(); +  sendSysex(msg, mmcStopMsgLen); +} + +//--------------------------------------------------------- +//   sendMMCDeferredPlay +//--------------------------------------------------------- + +void MidiPort::sendMMCDeferredPlay(int devid) +{ +  unsigned char msg[mmcDeferredPlayMsgLen]; +  memcpy(msg, mmcDeferredPlayMsg, mmcDeferredPlayMsgLen); +  if(devid != -1) +    msg[1] = devid; +  else +    msg[1] = _syncInfo.idOut(); +  sendSysex(msg, mmcDeferredPlayMsgLen); +} + +//---------------------------------------------------------  //   sendStart  //--------------------------------------------------------- diff --git a/muse/muse/midiport.h b/muse/muse/midiport.h index 33276845..9da238fb 100644 --- a/muse/muse/midiport.h +++ b/muse/muse/midiport.h @@ -91,6 +91,11 @@ class MidiPort {        void sendSongpos(int);        void sendClock();        void sendSysex(const unsigned char* p, int n); +      void sendMMCLocate(unsigned char ht, unsigned char m, +                         unsigned char s, unsigned char f, unsigned char sf, int devid = -1); +      void sendMMCStop(int devid = -1); +      void sendMMCDeferredPlay(int devid = -1); +              bool sendEvent(const MidiPlayEvent&);        AutomationType automationType(int channel) { return _automationType[channel]; }        void setAutomationType(int channel, AutomationType t) { diff --git a/muse/muse/midiseq.cpp b/muse/muse/midiseq.cpp index f3dfe870..2307203f 100644 --- a/muse/muse/midiseq.cpp +++ b/muse/muse/midiseq.cpp @@ -389,7 +389,6 @@ void MidiSeq::updatePollFd()        // (one fd for all devices)        //    this allows for processing of some alsa events        //    even if no alsa driver is active (assigned to a port) -        addPollFd(alsaSelectRfd(), POLLIN, ::alsaMidiRead, this, 0);        } diff --git a/muse/muse/midiseq.h b/muse/muse/midiseq.h index 8cce855a..a11820fe 100644 --- a/muse/muse/midiseq.h +++ b/muse/muse/midiseq.h @@ -60,9 +60,9 @@ class MidiSeq : public Thread {        virtual void processMsg(const ThreadMsg*);        void updatePollFd(); -      void mtcSyncMsg(const MTC& mtc, bool seekFlag); -      void mtcInputFull(const unsigned char* p, int n); -      void nonRealtimeSystemSysex(const unsigned char* p, int n); +      void mtcSyncMsg(const MTC&, int, bool); +      //void mtcInputFull(const unsigned char* p, int n); +      //void nonRealtimeSystemSysex(const unsigned char* p, int n);     public:        //MidiSeq(int prio, const char* name); @@ -80,7 +80,10 @@ class MidiSeq : public Thread {        void mtcInputQuarter(int, unsigned char);        void setSongPosition(int, int);        // void eventReceived(MidiRecordEvent& event); -      void mmcInput(const unsigned char* p, int n); +      //void mmcInput(const unsigned char* p, int n); +      void mmcInput(int, const unsigned char*, int); +      void mtcInputFull(int, const unsigned char*, int); +      void nonRealtimeSystemSysex(int, const unsigned char*, int);        void msgMsg(int id);        void msgProcess(); diff --git a/muse/muse/mtc.cpp b/muse/muse/mtc.cpp index 2921933e..647d6359 100644 --- a/muse/muse/mtc.cpp +++ b/muse/muse/mtc.cpp @@ -17,11 +17,13 @@ extern int mtcType;  //    global mtcType  //--------------------------------------------------------- -double MTC::time() const +double MTC::time(int type) const        {        double time = _h * 3600 + _m * 60 + _s;        double ft = 0.0; -      switch (mtcType) { +      if(type == -1) +        type = mtcType; +      switch (type) {              case 0:     // 24 frames sec                    ft = 1.0/24.0;                    break; @@ -30,6 +32,7 @@ double MTC::time() const                    break;              case 2:     // 30 drop frame        TODO              case 3:     // 30 non drop frame +            default:                    ft = 1.0/30.0;                    break;              } @@ -40,7 +43,7 @@ double MTC::time() const  //   MTC  //--------------------------------------------------------- -MTC::MTC(double t) +MTC::MTC(double t, int type)        {        _h  = int(t/3600);        t -= _h * 3600; @@ -49,7 +52,9 @@ MTC::MTC(double t)        _s  = int(t);        t -= _s;        double ft = 1.0/24.0; -      switch (mtcType) { +      if(type == -1) +        type = mtcType; +      switch (type) {              case 0:     // 24 frames sec                    ft = 1.0/24.0;                    break; @@ -58,6 +63,7 @@ MTC::MTC(double t)                    break;              case 2:     // 30 drop frame              case 3:     // 30 non drop frame +            default:                    ft = 1.0/30.0;                    break;              } @@ -72,10 +78,12 @@ MTC::MTC(double t)  //    increment MTC time one quarter frame time  //--------------------------------------------------------- -void MTC::incQuarter() +void MTC::incQuarter(int type)        {        int frames = 24; -      switch (mtcType) { +      if(type == -1) +        type = mtcType; +      switch (type) {              case 0:                    frames = 24;                    break; @@ -84,6 +92,7 @@ void MTC::incQuarter()                    break;              case 2:              case 3: +            default:                    frames = 30;                    break;              } diff --git a/muse/muse/mtc.h b/muse/muse/mtc.h index 658cd581..ae2bb01e 100644 --- a/muse/muse/mtc.h +++ b/muse/muse/mtc.h @@ -27,7 +27,7 @@ class MTC {        MTC() {              _h = _m = _s = _f = _sf = 0;              } -      MTC(double); +      MTC(double, int type = -1);        void set(int h, int m, int s, int f, int sf=0) {              _h  = h;              _m  = m; @@ -35,7 +35,7 @@ class MTC {              _f  = f;              _sf = sf;              } -      void incQuarter(); +      void incQuarter(int type = -1);        void setH(int val)  { _h = val; }        void setM(int val)  { _m = val; }        void setS(int val)  { _s = val; } @@ -47,7 +47,7 @@ class MTC {        int s() const  { return _s; }        int f() const  { return _f; }        int sf() const { return _sf; } -      double time() const; +      double time(int type = -1) const;        void print() const;        }; diff --git a/muse/muse/sync.cpp b/muse/muse/sync.cpp index 1d032cdd..141674dc 100644 --- a/muse/muse/sync.cpp +++ b/muse/muse/sync.cpp @@ -26,7 +26,9 @@  //MidiSyncPort midiSyncPorts[MIDI_PORTS];  int curMidiSyncInPort = -1; +// P3.3.26  bool debugSync = false; +  int mtcType     = 1;  MTC mtcOffset;  BValue extSyncFlag(0, "extSync");       // false - MASTER, true - SLAVE @@ -49,7 +51,11 @@ static bool mtcSync;    // receive complete mtc frame?  // static int mcStartTick;  // p3.3.25 -unsigned int midiExtSyncTicks = 0; +// From the "Introduction to the Volatile Keyword" at Embedded.com +/* A variable should be declared volatile whenever its value could change unexpectedly.  + ... <such as> global variables within a multi-threaded application     + ... So all shared global variables should be declared volatile */ +unsigned int volatile midiExtSyncTicks = 0;  //---------------------------------------------------------  //  MidiSyncInfo @@ -69,10 +75,17 @@ MidiSyncInfo::MidiSyncInfo()    _lastClkTime   = 0.0;    _lastTickTime  = 0.0; +  _lastMMCTime   = 0.0; +  _lastMTCTime   = 0.0;    _clockTrig     = false;    _tickTrig      = false; +  _MMCTrig       = false; +  _MTCTrig       = false;    _clockDetect   = false;    _tickDetect    = false; +  _MMCDetect     = false; +  _MTCDetect     = false; +  _recMTCtype    = 0;    _actDetectBits = 0;    for(int i = 0; i < MIDI_CHANNELS; ++i)    { @@ -94,10 +107,17 @@ MidiSyncInfo& MidiSyncInfo::operator=(const MidiSyncInfo &sp)    _lastClkTime   = sp._lastClkTime;    _lastTickTime  = sp._lastTickTime; +  _lastMMCTime   = sp._lastMMCTime; +  _lastMTCTime   = sp._lastMTCTime;    _clockTrig     = sp._clockTrig;    _tickTrig      = sp._tickTrig; +  _MMCTrig       = sp._MMCTrig; +  _MTCTrig       = sp._MTCTrig;    _clockDetect   = sp._clockDetect;    _tickDetect    = sp._tickDetect; +  _MMCDetect     = sp._MMCDetect; +  _MTCDetect     = sp._MTCDetect; +  _recMTCtype    = sp._recMTCtype;    _actDetectBits = sp._actDetectBits;    for(int i = 0; i < MIDI_CHANNELS; ++i)    { @@ -147,6 +167,7 @@ void MidiSyncInfo::setTime()    if(_clockDetect && (t - _lastClkTime >= 1.0)) // Set detect indicator timeout to about 1 second.    {      _clockDetect = false; +    // Give up the current midi sync in port number if we took it...      if(curMidiSyncInPort == _port)        curMidiSyncInPort = -1;    } @@ -160,6 +181,34 @@ void MidiSyncInfo::setTime()    if(_tickDetect && (t - _lastTickTime) >= 1.0) // Set detect indicator timeout to about 1 second.      _tickDetect = false; +  if(_MMCTrig) +  { +    _MMCTrig = false; +    _lastMMCTime = t;   +  } +  else +  if(_MMCDetect && (t - _lastMMCTime) >= 1.0) // Set detect indicator timeout to about 1 second. +  { +    _MMCDetect = false; +    // Give up the current midi sync in port number if we took it... +    //if(curMidiSyncInPort == _port) +    //  curMidiSyncInPort = -1; +  } +     +  if(_MTCTrig) +  { +    _MTCTrig = false; +    _lastMTCTime = t;   +  } +  else +  if(_MTCDetect && (t - _lastMTCTime) >= 1.0) // Set detect indicator timeout to about 1 second. +  { +    _MTCDetect = false; +    // Give up the current midi sync in port number if we took it... +    if(curMidiSyncInPort == _port) +      curMidiSyncInPort = -1; +  } +        for(int i = 0; i < MIDI_CHANNELS; i++)    {      if(_actTrig[i]) @@ -189,6 +238,30 @@ void MidiSyncInfo::setMCIn(const bool v)  }  //--------------------------------------------------------- +//  setMMCIn +//--------------------------------------------------------- + +void MidiSyncInfo::setMMCIn(const bool v)  +{  +  _recMMC = v;  +  // If sync receive was turned off, clear the current midi sync in port number so another port can grab it. +  //if(!_recMMC && _port != -1 && curMidiSyncInPort == _port) +  //  curMidiSyncInPort = -1; +} + +//--------------------------------------------------------- +//  setMTCIn +//--------------------------------------------------------- + +void MidiSyncInfo::setMTCIn(const bool v)  +{  +  _recMTC = v;  +  // If sync receive was turned off, clear the current midi sync in port number so another port can grab it. +  if(!_recMTC && _port != -1 && curMidiSyncInPort == _port) +    curMidiSyncInPort = -1; +} + +//---------------------------------------------------------  //  trigMCSyncDetect  //--------------------------------------------------------- @@ -212,6 +285,32 @@ void MidiSyncInfo::trigTickDetect()  }  //--------------------------------------------------------- +//  trigMMCDetect +//--------------------------------------------------------- + +void MidiSyncInfo::trigMMCDetect()    +{  +  _MMCDetect = true; +  _MMCTrig = true; +  // Set the current midi sync in port number if it's not taken... +  //if(_recMMC && curMidiSyncInPort == -1) +  //  curMidiSyncInPort = _port; +} +     +//--------------------------------------------------------- +//  trigMTCDetect +//--------------------------------------------------------- + +void MidiSyncInfo::trigMTCDetect()    +{  +  _MTCDetect = true; +  _MTCTrig = true; +  // Set the current midi sync in port number if it's not taken... +  if(_recMTC && curMidiSyncInPort == -1) +    curMidiSyncInPort = _port; +} +     +//---------------------------------------------------------  //  actDetect  //--------------------------------------------------------- @@ -327,15 +426,29 @@ void MidiSyncInfo::write(int level, Xml& xml)  //    Midi Machine Control Input received  //--------------------------------------------------------- -void MidiSeq::mmcInput(const unsigned char* p, int n) +//void MidiSeq::mmcInput(const unsigned char* p, int n) +void MidiSeq::mmcInput(int port, const unsigned char* p, int n)        {        if (debugSync)              printf("mmcInput: n:%d %02x %02x %02x %02x\n",                 n, p[2], p[3], p[4], p[5]); +      +      MidiPort* mp = &midiPorts[port]; +      MidiSyncInfo& msync = mp->syncInfo(); +      // Trigger MMC detect in. +      msync.trigMMCDetect(); +      // MMC locate SMPTE time code may contain format type bits. Grab them. +      if(p[3] == 0x44 && p[4] == 6 && p[5] == 1) +        msync.setRecMTCtype((p[6] >> 5) & 3); +       +      // MMC in not turned on? Forget it. +      if(!msync.MMCIn()) +        return; +              //if (!(extSyncFlag.value() && acceptMMC)) -      if(!extSyncFlag.value()) -            return; - +      //if(!extSyncFlag.value()) +      //      return; +              switch(p[3]) {              case 1:                    if (debugSync) @@ -384,18 +497,22 @@ void MidiSeq::mmcInput(const unsigned char* p, int n)                          break;                          }                    else if (p[5] == 1) { +                        if (!checkAudioDevice()) return;                          MTC mtc(p[6] & 0x1f, p[7], p[8], p[9], p[10]); -                        int mmcPos = tempomap.frame2tick(lrint(mtc.time()*sampleRate)); +                        int type = (p[6] >> 5) & 3; +                        //int mmcPos = tempomap.frame2tick(lrint(mtc.time()*sampleRate)); +                        //int mmcPos = lrint(mtc.time()*sampleRate); +                        int mmcPos = lrint(mtc.time(type) * sampleRate); -                        Pos tp(mmcPos, true); -                        if (!checkAudioDevice()) return; +                        //Pos tp(mmcPos, true); +                        Pos tp(mmcPos, false);                          //audioDevice->seekTransport(tp.frame());                          audioDevice->seekTransport(tp);                          alignAllTicks();                          //seek(tp);                          if (debugSync) { -                              printf("MMC: %f %d seek ", -                                 mtc.time(), mmcPos); +                              //printf("MMC: %f %d seek ", mtc.time(), mmcPos); +                              printf("MMC: LOCATE mtc type:%d time:%lf frame:%d mtc: ", type, mtc.time(), mmcPos);                                mtc.print();                                printf("\n");                                } @@ -413,13 +530,11 @@ void MidiSeq::mmcInput(const unsigned char* p, int n)  //    process Quarter Frame Message  //--------------------------------------------------------- -void MidiSeq::mtcInputQuarter(int, unsigned char c) +//void MidiSeq::mtcInputQuarter(int, unsigned char c) +void MidiSeq::mtcInputQuarter(int port, unsigned char c)        {        static int hour, min, sec, frame; -      if (!extSyncFlag.value()) -            return; -        int valL = c & 0xf;        int valH = valL << 4; @@ -456,35 +571,55 @@ void MidiSeq::mtcInputQuarter(int, unsigned char c)        frame &= 0x1f;    // 0-29        sec   &= 0x3f;    // 0-59        min   &= 0x3f;    // 0-59 +      int tmphour = hour; +      int type = (hour >> 5) & 3;        hour  &= 0x1f; -      if (mtcState == 8) { +      if(mtcState == 8)  +      {              mtcValid = (mtcLost == 0);              mtcState = 0;              mtcLost  = 0; -            if (mtcValid) { +            if(mtcValid)  +            {                    mtcCurTime.set(hour, min, sec, frame); -                  mtcSyncMsg(mtcCurTime, !mtcSync); -                  mtcSync = true; +                  if(port != -1) +                  { +                    MidiPort* mp = &midiPorts[port]; +                    MidiSyncInfo& msync = mp->syncInfo(); +                    msync.setRecMTCtype(type); +                    msync.trigMTCDetect(); +                    // Not for the current in port? External sync not turned on? MTC in not turned on? Forget it. +                    if(port == curMidiSyncInPort && extSyncFlag.value() && msync.MTCIn())  +                    { +                      if(debugSync) +                        printf("mtcInputQuarter: hour byte:%hx\n", tmphour); +                      mtcSyncMsg(mtcCurTime, type, !mtcSync); +                    }                      } +                  mtcSync = true;              } -      else if (mtcValid && (mtcLost == 0)) { -            mtcCurTime.incQuarter(); -            mtcSyncMsg(mtcCurTime, false); -            } +      }       +      else if (mtcValid && (mtcLost == 0))  +      { +            //mtcCurTime.incQuarter(); +            mtcCurTime.incQuarter(type); +            //mtcSyncMsg(mtcCurTime, type, false);        } +    }  //---------------------------------------------------------  //   mtcInputFull  //    process Frame Message  //--------------------------------------------------------- -void MidiSeq::mtcInputFull(const unsigned char* p, int n) +//void MidiSeq::mtcInputFull(const unsigned char* p, int n) +void MidiSeq::mtcInputFull(int port, const unsigned char* p, int n)        {        if (debugSync)              printf("mtcInputFull\n"); -      if (!extSyncFlag.value()) -            return; +      //if (!extSyncFlag.value()) +      //      return;        if (p[3] != 1) {              if (p[3] != 2) {   // silently ignore user bits @@ -501,20 +636,41 @@ void MidiSeq::mtcInputFull(const unsigned char* p, int n)        frame &= 0x1f;    // 0-29        sec   &= 0x3f;    // 0-59        min   &= 0x3f;    // 0-59 -//      int type = (hour >> 5) & 3; +      int type = (hour >> 5) & 3;        hour &= 0x1f;        mtcCurTime.set(hour, min, sec, frame);        mtcState = 0;        mtcValid = true;        mtcLost  = 0; -      } +       +      // Added by Tim. +      if(debugSync) +        printf("mtcInputFull: time:%lf stime:%lf hour byte (all bits):%hx\n", mtcCurTime.time(), mtcCurTime.time(type), p[4]); +      if(port != -1) +      { +        MidiPort* mp = &midiPorts[port]; +        MidiSyncInfo& msync = mp->syncInfo(); +        msync.setRecMTCtype(type); +        msync.trigMTCDetect(); +        // MTC in not turned on? Forget it. +        //if(extSyncFlag.value() && msync.MTCIn()) +        if(msync.MTCIn()) +        { +          //Pos tp(lrint(mtcCurTime.time() * sampleRate), false); +          Pos tp(lrint(mtcCurTime.time(type) * sampleRate), false); +          audioDevice->seekTransport(tp); +          alignAllTicks(); +        } +      }     +    }  //---------------------------------------------------------  //   nonRealtimeSystemSysex  //--------------------------------------------------------- -void MidiSeq::nonRealtimeSystemSysex(const unsigned char* p, int n) +//void MidiSeq::nonRealtimeSystemSysex(const unsigned char* p, int n) +void MidiSeq::nonRealtimeSystemSysex(int /*port*/, const unsigned char* p, int n)        {  //      int chan = p[2];        switch(p[3]) { @@ -660,6 +816,7 @@ void MidiSeq::realtimeSystemInput(int port, int c)                      midiExtSyncTicks += div;                    } +//BEGIN : Original code:                    /*                    double mclock0 = curTime();                    // Difference in time last 2 rounds: @@ -771,6 +928,142 @@ void MidiSeq::realtimeSystemInput(int port, int c)                    mclock2 = mclock1;                    mclock1 = mclock0;                    */ +//END : Original Code +                   +//BEGIN : Using external tempo map: +                  /* +                  double mclock0 = curTime(); +                  // Difference in time last 2 rounds: +                  double tdiff0   = mclock0 - mclock1; +                  double tdiff1   = mclock1 - mclock2; +                  double averagetimediff = 0.0; + +                  if (mclock1 != 0.0) { +                        if (storedtimediffs < 24) +                        { +                           timediff[storedtimediffs] = mclock0 - mclock1; +                           storedtimediffs++; +                        } +                        else { +                              for (int i=0; i<23; i++) { +                                    timediff[i] = timediff[i+1]; +                                    } +                              timediff[23] = mclock0 - mclock1; +                        } +                        // Calculate average timediff: +                        for (int i=0; i < storedtimediffs; i++) { +                              averagetimediff += timediff[i]/storedtimediffs; +                              } +                        } + +                  // Compare w audio if playing: +                  //if (playStateExt == true ) {  //audio->isPlaying()  state == PLAY +                  if (0) { +                        //BEGIN standard setup: +                        recTick  += config.division / 24; // The one we're syncing to +                        int tempo = tempomap.tempo(0); +                        //unsigned curFrame = audio->pos().frame(); +                        //double songtick = (double(curFrame)/double(sampleRate)) * +                        //                   double(config.division * 1000000.0) / double(tempo); +                        double songtick = tempomap.curTickExt(mclock0); +                         +                        double scale = double(tdiff0/averagetimediff); +                        double tickdiff = songtick - ((double) recTick - 24 + scale*24.0); + +                        //END standard setup +                        if (debugSync) { +                              int m, b, t; +                              audio->pos().mbt(&m, &b, &t); + +                              int song_beat = b + m*4; // if the time-signature is different than 4/4, this will be wrong. +                              int sync_beat = recTick/config.division; +                              printf("pT=%.3f rT=%d diff=%.3f songB=%d syncB=%d scale=%.3f, curFrame=%d averagetimediff:%.3lf",  +                                      songtick, recTick, tickdiff, song_beat, sync_beat, scale, audio->pos().frame(), averagetimediff); +                              } + +                        //if ((mclock2 !=0.0) && (tdiff1 > 0.0) && fabs(tickdiff) > 0.5 && lastTempo != 0) { +                        if ((mclock2 !=0.0) && (tdiff1 > 0.0) && lastTempo != 0) { +                              // Interpolate: +                              double tickdiff1 = songtick1 - recTick1; +                              double tickdiff2 = songtick2 - recTick2; +                              double newtickdiff = (tickdiff1+tickdiff2)/250;  +                              ////double newtickdiff = (tickdiff1+tickdiff2) / 10.0;  +                              //double newtickdiff = tickdiff/5.0  + +                              //                     tickdiff1/16.0 + +                              //                     tickdiff2/24.0;  //5 mins 30 secs on 116BPM, -p 512 jackd + +                              if (newtickdiff != 0.0) { +                                    //int newTempo = tempomap.tempo(0); +                                    int newTempo = tempo; +                                    //newTempo += int(24.0 * newtickdiff * scale); +                                    newTempo += int(24.0 * newtickdiff); +                                    if (debugSync) +                                          printf(" tdiff=%f ntd=%f lt=%d tmpo=%.3f",  +                                                tdiff0, newtickdiff, lastTempo, (float)((1000000.0 * 60.0)/newTempo)); +                                    //syncTempo = newTempo; +                                    //tempomap.setTempo(0,newTempo); +                                    // Don't set the last stable tempo. +                                    //tempomap.setTempo(0, newTempo, false); +                                    tempomap.setExtTempo(newTempo); +                                    } +                              if (debugSync) +                                    printf("\n"); +                              } +                        else if (debugSync) +                              printf("\n"); + +                        //BEGIN post calc +                        lastTempo = tempo; +                        recTick2 = recTick1; +                        recTick1 = recTick; +                        mclock2 = mclock1; +                        mclock1 = mclock0; +                        songtick2 = songtick1; +                        songtick1 = songtick; +                        //END post calc +                        break; +                        } // END state play +                  // +                  // Pre-sync (when audio is not running) +                  // Calculate tempo depending on time per pulse +                  // +                  if (mclock1 == 0.0) { +                        mp->device()->discardInput(); +                        if (debugSync) +                           printf("Discarding input from port %d\n", port); +                        } +                  if ((mclock2 != 0.0) && (tdiff0 > 0.0)) { +                         +                        //int tempo0 = int(24000000.0 * tdiff0 + .5); +                        //int tempo1 = int(24000000.0 * tdiff1 + .5); +                        //int tempo = tempomap.tempo(0); +                        //int diff0 = tempo0 - tempo; +                        //int diff1 = tempo1 - tempo0; +                         +                        //if (diff0) { +                        //      int newTempo = tempo + diff0/8 + diff1/16; +                        //      if (debugSync) +                        //         printf("setting new tempo %d = %f\n", newTempo, (float)((1000000.0 * 60.0)/newTempo)); +                              //tempomap.setTempo(0, newTempo); +                              // Don't set the last stable tempo. +                              //tempomap.setTempo(0, newTempo, false); +                        //      tempomap.setExtTempo(newTempo); +                        //      } +                         +                        //double tempo0 = 24000000.0 * tdiff0; +                        //double tempo1 = 24000000.0 * tdiff1; +                        //int newTempo = int((tempo0 + tempo1) / 2.0); +                        int newTempo = int(averagetimediff * 24000000.0); +                        if(debugSync) +                          printf("setting new tempo %d = %f\n", newTempo, (float)((1000000.0 * 60.0)/newTempo)); +                        tempomap.setExtTempo(newTempo); +                        } +                         +                  mclock2 = mclock1; +                  mclock1 = mclock0; +                  */ +//END : Using external tempo map +                                      }                    break;              case 0xf9:  // midi tick  (every 10 msec) @@ -793,6 +1086,7 @@ void MidiSeq::realtimeSystemInput(int port, int c)                          if (!checkAudioDevice()) return;                          //audioDevice->seekTransport(0);                          audioDevice->seekTransport(Pos(0, false)); +                          unsigned curFrame = audio->curFrame();                          if (debugSync)                                printf("       curFrame=%d\n", curFrame); @@ -804,7 +1098,13 @@ void MidiSeq::realtimeSystemInput(int port, int c)                          storedtimediffs = 0;                          for (int i=0; i<24; i++)                                timediff[i] = 0.0; -                        audio->msgPlay(true); +                         +                        // p3.3.26 1/23/10 +                        // Changed because msgPlay calls audioDevice->seekTransport(song->cPos()) +                        //  and song->cPos() may not be changed to 0 yet, causing tranport not to go to 0. +                        //audio->msgPlay(true); +                        audioDevice->startTransport(); +                                                  playStateExt = true;                          }                    break; @@ -815,7 +1115,7 @@ void MidiSeq::realtimeSystemInput(int port, int c)                        midiPorts[p].sendContinue();                    if (debugSync) -                        printf("   continue\n"); +                        printf("realtimeSystemInput continue\n");                    if (1 /* !audio->isPlaying() */ /*state == IDLE */) {                          //unsigned curFrame = audio->curFrame();                          //recTick = tempomap.frame2tick(curFrame); // don't think this will work... (ml) @@ -831,7 +1131,7 @@ void MidiSeq::realtimeSystemInput(int port, int c)                        midiPorts[p].sendStop();                    if (debugSync) -                        printf("   stop\n"); +                        printf("realtimeSystemInput stop\n");                    if (audio->isPlaying() /*state == PLAY*/) {                          audio->msgPlay(false);                          playStateExt = false; @@ -852,17 +1152,20 @@ void MidiSeq::realtimeSystemInput(int port, int c)  //                start  //--------------------------------------------------------- -void MidiSeq::mtcSyncMsg(const MTC& mtc, bool seekFlag) +void MidiSeq::mtcSyncMsg(const MTC& mtc, int type, bool seekFlag)        {        double time = mtc.time(); +      double stime = mtc.time(type);        if (debugSync) -            printf("mtcSyncMsg: time %f\n", time); +            printf("mtcSyncMsg: time:%lf stime:%lf seekFlag:%d\n", time, stime, seekFlag);        if (seekFlag && audio->isRunning() /*state == START_PLAY*/) {  //            int tick = tempomap.time2tick(time);              //state = PLAY;              //write(sigFd, "1", 1);  // say PLAY to gui              if (!checkAudioDevice()) return; +            if (debugSync) +              printf("mtcSyncMsg: starting transport.\n");              audioDevice->startTransport();              return;              } diff --git a/muse/muse/sync.h b/muse/muse/sync.h index f09d410c..b5a75fb8 100644 --- a/muse/muse/sync.h +++ b/muse/muse/sync.h @@ -32,14 +32,22 @@ class MidiSyncInfo      bool _recMMC;      bool _recMTC; +    int _recMTCtype; +          double   _lastClkTime;      double   _lastTickTime; +    double   _lastMMCTime; +    double   _lastMTCTime;      double   _lastActTime[MIDI_CHANNELS];      bool     _clockTrig;      bool     _tickTrig; +    bool     _MMCTrig; +    bool     _MTCTrig;      bool     _actTrig[MIDI_CHANNELS];      bool     _clockDetect;      bool     _tickDetect; +    bool     _MMCDetect; +    bool     _MTCDetect;      bool     _actDetect[MIDI_CHANNELS];      int      _actDetectBits; @@ -69,8 +77,8 @@ class MidiSyncInfo      void setMTCOut(const bool v)  { _sendMTC = v; }      void setMCIn(const bool v);    -    void setMMCIn(const bool v)   { _recMMC = v; } -    void setMTCIn(const bool v)   { _recMTC = v; } +    void setMMCIn(const bool v);    +    void setMTCIn(const bool v);         void setTime();  @@ -80,6 +88,14 @@ class MidiSyncInfo      bool tickDetect() const       { return _tickDetect; }                 void trigTickDetect(); +    bool MTCDetect() const       { return _MTCDetect; }            +    void trigMTCDetect(); +    int recMTCtype() const       { return _recMTCtype; } +    void setRecMTCtype(int t)    { _recMTCtype = t; } +     +    bool MMCDetect() const       { return _MMCDetect; }            +    void trigMMCDetect(); +          int  actDetectBits() const    { return _actDetectBits; }      bool actDetect(const int ch) const;      void trigActDetect(const int ch); diff --git a/muse/muse/widgets/midisyncimpl.cpp b/muse/muse/widgets/midisyncimpl.cpp index d38068fc..cbae9cb2 100644 --- a/muse/muse/widgets/midisyncimpl.cpp +++ b/muse/muse/widgets/midisyncimpl.cpp @@ -31,8 +31,11 @@  #include "sync.h"  #include "globals.h"  #include "midisyncimpl.h" +#include "driver/audiodev.h" +#include "audio.h" -enum { DEVCOL_NO = 0, DEVCOL_NAME, DEVCOL_IN, DEVCOL_TICKIN, DEVCOL_RID, DEVCOL_RCLK, DEVCOL_RMMC, DEVCOL_RMTC,  +//enum { DEVCOL_NO = 0, DEVCOL_NAME, DEVCOL_IN, DEVCOL_TICKIN, DEVCOL_RID, DEVCOL_RCLK, DEVCOL_RMMC, DEVCOL_RMTC,  +enum { DEVCOL_NO = 0, DEVCOL_NAME, DEVCOL_IN, DEVCOL_TICKIN, DEVCOL_MMCIN, DEVCOL_MTCIN, DEVCOL_MTCTYPE, DEVCOL_RID, DEVCOL_RCLK, DEVCOL_RMMC, DEVCOL_RMTC,   //enum { DEVCOL_NAME = 0, DEVCOL_IN, DEVCOL_RID, DEVCOL_RCLK, DEVCOL_RMMC, DEVCOL_RMTC,          DEVCOL_TID, DEVCOL_TCLK, DEVCOL_TMMC, DEVCOL_TMTC }; @@ -57,11 +60,14 @@ void MSyncHeaderTip::maybeTip(const QPoint &pos)                         " this port number"); break;              case DEVCOL_IN:       p = QHeader::tr("Midi realtime input detected"); break;              case DEVCOL_TICKIN:   p = QHeader::tr("Midi tick input detected"); break; -            case DEVCOL_RID:      p = QHeader::tr("Receive id number. Double click to edit."); break; +            case DEVCOL_MMCIN:    p = QHeader::tr("MMC input detected"); break; +            case DEVCOL_MTCIN:    p = QHeader::tr("MTC input detected"); break; +            case DEVCOL_MTCTYPE:  p = QHeader::tr("Detected SMPTE format"); break; +            case DEVCOL_RID:      p = QHeader::tr("Receive id number. 127 = Global. Double click to edit."); break;              case DEVCOL_RCLK:     p = QHeader::tr("Accept midi realtime input"); break;              case DEVCOL_RMMC:     p = QHeader::tr("Accept MMC input"); break;              case DEVCOL_RMTC:     p = QHeader::tr("Accept MTC input"); break; -            case DEVCOL_TID:      p = QHeader::tr("Transmit id number. Double click to edit."); break; +            case DEVCOL_TID:      p = QHeader::tr("Transmit id number. 127 = Global. Double click to edit."); break;              case DEVCOL_TCLK:     p = QHeader::tr("Send midi realtime output"); break;              case DEVCOL_TMMC:     p = QHeader::tr("Send MMC output"); break;              case DEVCOL_TMTC:     p = QHeader::tr("Send MTC output"); break; @@ -85,26 +91,36 @@ QString MSyncWhatsThis::text(const QPoint& pos)              case DEVCOL_NAME:                    return QHeader::tr("Name of the midi device associated with this port number");              case DEVCOL_IN: -                  return QHeader::tr("Midi realtime input detected, including clock/start/stop/continue, and song position. " +                  return QHeader::tr("Midi realtime input detected, including clock/start/stop/continue, and song position.\n"                                       "Current port actually used is red. Click to force a port to be current.");              case DEVCOL_TICKIN:                    return QHeader::tr("Midi tick input detected"); +            case DEVCOL_MMCIN: +                  return QHeader::tr("MMC input detected, including stop/play/deferred play, and locate."); +                                     //"Current port actually used is red. Click to force a port to be current."); +            case DEVCOL_MTCIN: +                  return QHeader::tr("MTC input detected, including forward quarter-frame sync and full-frame locate.\n" +                                     "Current port actually used is red. Click to force a port to be current."); +            case DEVCOL_MTCTYPE: +                  return QHeader::tr("Detected SMPTE format: 24fps, 25fps, 30fps drop frame, or 30fps non-drop\n" +                                     "Detects format of MTC quarter and full frame, and MMC locate.");              case DEVCOL_RID: -                  return QHeader::tr("Receive id number"); +                  return QHeader::tr("Receive id number. 127 = global receive all, even if not global.");              case DEVCOL_RCLK: -                  return QHeader::tr("Accept midi realtime input, including clock/start/stop/continue, and song position. " -                                     "Only one input is used for clock. Auto-acquire: If two or more port realtime inputs " -                                     "are enabled, the first clock detected is used, until clock is lost, then another " -                                     "can take over. Non-clock events (start,stop etc) are accepted by ALL enabled ports. " -                                     "This means you may have several master devices connected, and muse will accept input " -                                     "from any, including one clock (best if each turns off its clock at stop, so muse can " -                                     "re-acquire the clock from another port. Click on detect indicator to force another.) "); +                  return QHeader::tr("Accept midi realtime input, including clock/start/stop/continue, and song position.\n" +                                     "Only one input is used for clock. Auto-acquire: If two or more port realtime inputs\n" +                                     "are enabled, the first clock detected is used, until clock is lost, then another\n" +                                     "can take over. Non-clock events (start,stop etc) are accepted by ALL enabled ports.\n" +                                     "This means you may have several master devices connected, and muse will accept input\n" +                                     "from any, including one clock (best if each turns off its clock at stop, so muse can\n" +                                     "re-acquire the clock from another port. Click on detect indicator to force another.)");              case DEVCOL_RMMC: -                  return QHeader::tr("Accept MMC input"); +                  return QHeader::tr("Accept MMC input, including stop/play/deferred play, and locate.");              case DEVCOL_RMTC: -                  return QHeader::tr("Accept MTC input"); +                  return QHeader::tr("Accept MTC input, including forward quarter-frame sync and full-frame locate.\n" +                                     "See rmc column for more help.");              case DEVCOL_TID: -                  return QHeader::tr("Transmit id number"); +                  return QHeader::tr("Transmit id number. 127 = global transmit to all.");              case DEVCOL_TCLK:                    return QHeader::tr("Send midi realtime output, including clock/start/stop/continue, and song position. "                                       "If 'Slave to External Sync' is chosen, muse can re-transmit midi realtime input " @@ -237,6 +253,9 @@ MidiSyncConfig::MidiSyncConfig(QWidget* parent, const char* name)        devicesListView->addColumn(tr("Device Name"), 120);        devicesListView->addColumn(tr("i"));        devicesListView->addColumn(tr("t")); +      devicesListView->addColumn(tr("m")); +      devicesListView->addColumn(tr("c")); +      devicesListView->addColumn(tr("type"));        devicesListView->addColumn(tr("rid"));  // Receive        devicesListView->addColumn(tr("rmc")); // Receive        devicesListView->addColumn(tr("rmmc")); // Receive @@ -250,6 +269,9 @@ MidiSyncConfig::MidiSyncConfig(QWidget* parent, const char* name)        devicesListView->setColumnAlignment(DEVCOL_NO, AlignHCenter);        devicesListView->setColumnAlignment(DEVCOL_IN, AlignCenter);        devicesListView->setColumnAlignment(DEVCOL_TICKIN, AlignCenter); +      devicesListView->setColumnAlignment(DEVCOL_MMCIN, AlignCenter); +      devicesListView->setColumnAlignment(DEVCOL_MTCIN, AlignCenter); +      //devicesListView->setColumnAlignment(DEVCOL_MTCTYPE, AlignCenter);        //devicesListView->setColumnAlignment(DEVCOL_RID, AlignCenter);        devicesListView->setColumnAlignment(DEVCOL_RCLK, AlignCenter);        devicesListView->setColumnAlignment(DEVCOL_RMMC, AlignCenter); @@ -261,6 +283,7 @@ MidiSyncConfig::MidiSyncConfig(QWidget* parent, const char* name)        devicesListView->header()->setResizeEnabled(false, DEVCOL_NO);        devicesListView->header()->setResizeEnabled(false, DEVCOL_IN);        devicesListView->header()->setResizeEnabled(false, DEVCOL_TICKIN); +      devicesListView->header()->setResizeEnabled(false, DEVCOL_MTCIN);        devicesListView->header()->setResizeEnabled(false, DEVCOL_RCLK);        devicesListView->header()->setResizeEnabled(false, DEVCOL_RMMC);        devicesListView->header()->setResizeEnabled(false, DEVCOL_RMTC); @@ -270,6 +293,7 @@ MidiSyncConfig::MidiSyncConfig(QWidget* parent, const char* name)        //devicesListView->setResizeMode(QListView::LastColumn);        devicesListView->setResizeMode(QListView::NoColumn); +        new MSyncWhatsThis(devicesListView, devicesListView->header());        _synctooltip = new MSyncHeaderTip(devicesListView->header());        //MSyncHeaderTip::add(devicesListView->header(), QString("Midi sync ports")); @@ -295,6 +319,7 @@ MidiSyncConfig::MidiSyncConfig(QWidget* parent, const char* name)        connect(extSyncCheckbox, SIGNAL(clicked()), SLOT(syncChanged()));        connect(mtcSyncType, SIGNAL(activated(int)), SLOT(syncChanged()));        connect(useJackTransportCheckbox, SIGNAL(clicked()), SLOT(syncChanged())); +      //connect(jackTransportMasterCheckbox, SIGNAL(clicked()), SLOT(syncChanged()));        connect(&extSyncFlag, SIGNAL(valueChanged(bool)), SLOT(extSyncChanged(bool))); @@ -333,18 +358,32 @@ void MidiSyncConfig::songChanged(int flags)        extSyncCheckbox->blockSignals(true);        useJackTransportCheckbox->blockSignals(true); +      //jackTransportMasterCheckbox->blockSignals(true);        extSyncCheckbox->setChecked(extSyncFlag.value());        useJackTransportCheckbox->setChecked(useJackTransport); +      //jackTransportMasterCheckbox->setChecked(jackTransportMaster); +      //jackTransportMasterCheckbox->setEnabled(useJackTransport); +      //jackTransportMasterCheckbox->blockSignals(false);        useJackTransportCheckbox->blockSignals(false);        extSyncCheckbox->blockSignals(false);        mtcSyncType->setCurrentItem(mtcType); +      mtcOffH->blockSignals(true); +      mtcOffM->blockSignals(true); +      mtcOffS->blockSignals(true); +      mtcOffF->blockSignals(true); +      mtcOffSf->blockSignals(true);        mtcOffH->setValue(mtcOffset.h());        mtcOffM->setValue(mtcOffset.m());        mtcOffS->setValue(mtcOffset.s());        mtcOffF->setValue(mtcOffset.f());        mtcOffSf->setValue(mtcOffset.sf()); +      mtcOffH->blockSignals(false); +      mtcOffM->blockSignals(false); +      mtcOffS->blockSignals(false); +      mtcOffF->blockSignals(false); +      mtcOffSf->blockSignals(false);        updateSyncInfoLV(); @@ -427,7 +466,118 @@ void MidiSyncConfig::heartBeat()                lvi->setPixmap(DEVCOL_TICKIN, *dothIcon);              }              } +         +          int type = midiPorts[port].syncInfo().recMTCtype(); +          sdet = midiPorts[port].syncInfo().MMCDetect(); +          bool mtcdet = midiPorts[port].syncInfo().MTCDetect(); +          if(sdet) +          { +            if(!lvi->_MMCDet) +            { +              // Added by Tim. p3.3.6 +              //printf("MidiSyncConfig::heartBeat setting MMC on icon\n"); +           +              lvi->_MMCDet = true; +              lvi->setPixmap(DEVCOL_MMCIN, *dotIcon); +            } +            // MMC locate command can contain SMPTE format type. Update now. +            if(!mtcdet && lvi->_recMTCtype != type) +            { +              lvi->_recMTCtype = type; +              switch(type) +              { +                case 0: +                  lvi->setText(DEVCOL_MTCTYPE, "24"); +                break;   +                case 1: +                  lvi->setText(DEVCOL_MTCTYPE, "25"); +                break;   +                case 2: +                  lvi->setText(DEVCOL_MTCTYPE, "30D"); +                break;   +                case 3: +                  lvi->setText(DEVCOL_MTCTYPE, "30N"); +                break;   +                default: +                  lvi->setText(DEVCOL_MTCTYPE, "??"); +                break;   +              }   +            } +          }  +          else +          { +            if(lvi->_MMCDet) +            { +              // Added by Tim. p3.3.6 +              //printf("MidiSyncConfig::heartBeat setting MMC off icon\n"); +           +              lvi->_MMCDet = false; +              lvi->setPixmap(DEVCOL_MMCIN, *dothIcon); +            }   +          } +           +          if(mtcdet) +          { +            if(port == curMidiSyncInPort) +            { +              if(!lvi->_curMTCDet) +              { +                // Added by Tim. p3.3.6 +                //printf("MidiSyncConfig::heartBeat setting current red icon\n"); +             +                lvi->_curMTCDet = true; +                lvi->_MTCDet = false; +                lvi->setPixmap(DEVCOL_MTCIN, *record1_Icon); +              }   +            } +            else +            if(!lvi->_MTCDet) +            { +              // Added by Tim. p3.3.6 +              //printf("MidiSyncConfig::heartBeat setting MTC on icon\n"); +           +              lvi->_MTCDet = true; +              lvi->_curMTCDet = false; +              lvi->setPixmap(DEVCOL_MTCIN, *dotIcon); +            } +             +            if(lvi->_recMTCtype != type) +            { +              lvi->_recMTCtype = type; +              switch(type) +              { +                case 0: +                  lvi->setText(DEVCOL_MTCTYPE, "24"); +                break;   +                case 1: +                  lvi->setText(DEVCOL_MTCTYPE, "25"); +                break;   +                case 2: +                  lvi->setText(DEVCOL_MTCTYPE, "30D"); +                break;   +                case 3: +                  lvi->setText(DEVCOL_MTCTYPE, "30N"); +                break;   +                default: +                  lvi->setText(DEVCOL_MTCTYPE, "??"); +                break;   +              }   +            } +          }  +          else +          { +            if(lvi->_curMTCDet || lvi->_MTCDet) +            { +              // Added by Tim. p3.3.6 +              //printf("MidiSyncConfig::heartBeat setting MTC off icon\n"); +           +              lvi->_MTCDet = false; +              lvi->_curMTCDet = false; +              lvi->setPixmap(DEVCOL_MTCIN, *dothIcon); +            }   +          }          } +                  //MidiDevice* dev = lvi->device();          //bool sdet = dev->syncInfo().MCSyncDetect();          //if(lvi->pixmap(DEVCOL_IN) != (sdet ? *dotIcon : *dothIcon)) @@ -449,6 +599,8 @@ void MidiSyncConfig::syncChanged()        {        setDirty(); +      //jackTransportMasterCheckbox->setEnabled(useJackTransport); +              //acceptMTCCheckbox->setEnabled(val);  //      acceptMTCCheckbox->setEnabled(false);  //      acceptMCCheckbox->setEnabled(val); @@ -557,6 +709,13 @@ void MidiSyncConfig::apply()  //        song->setMasterFlag(false);        //extSyncFlag.blockSignals(false);        useJackTransport = useJackTransportCheckbox->isChecked(); +//      if(useJackTransport) +//        jackTransportMaster = jackTransportMasterCheckbox->isChecked(); +//      else   +//        jackTransportMaster = false; +//      jackTransportMasterCheckbox->setEnabled(useJackTransport); +//      if(audioDevice) +//        audioDevice->setMaster(jackTransportMaster);              mtcOffset.setH(mtcOffH->value());        mtcOffset.setM(mtcOffM->value()); @@ -589,7 +748,8 @@ void MidiSyncConfig::apply()    if(applyButton->isEnabled())      applyButton->setEnabled(false); -  midiSeq->msgUpdatePollFd(); +  // Do not call this. Causes freeze sometimes. Only will be needed if extra pollfds are used by midi seq thread. +  //midiSeq->msgUpdatePollFd();  }  //--------------------------------------------------------- @@ -652,6 +812,84 @@ void MidiSyncConfig::updateSyncInfoLV()                lvi->setPixmap(DEVCOL_TICKIN, *dothIcon);              } +            if(portsi.MMCDetect()) +            { +              lvi->_MMCDet = true; +              lvi->setPixmap(DEVCOL_MMCIN, *dotIcon); +              // MMC locate command can have SMPTE format bits... +              if(lvi->_recMTCtype != portsi.recMTCtype()) +              { +                switch(portsi.recMTCtype()) +                { +                  case 0: +                    lvi->setText(DEVCOL_MTCTYPE, "24"); +                  break;   +                  case 1: +                    lvi->setText(DEVCOL_MTCTYPE, "25"); +                  break;   +                  case 2: +                    lvi->setText(DEVCOL_MTCTYPE, "30D"); +                  break;   +                  case 3: +                    lvi->setText(DEVCOL_MTCTYPE, "30N"); +                  break;   +                  default: +                    lvi->setText(DEVCOL_MTCTYPE, "??"); +                  break;   +                }   +              }   +            } +            else +            { +              lvi->_MMCDet = false; +              lvi->setPixmap(DEVCOL_MMCIN, *dothIcon); +            } +             +            if(portsi.MTCDetect()) +            { +              if(i == curMidiSyncInPort) +              { +                lvi->_curMTCDet = true; +                lvi->_MTCDet = false; +                lvi->setPixmap(DEVCOL_MTCIN, *record1_Icon); +              } +              else +              { +                lvi->_curMTCDet = false; +                lvi->_MTCDet = true; +                lvi->setPixmap(DEVCOL_MTCIN, *dotIcon); +              } +                 +              if(lvi->_recMTCtype != portsi.recMTCtype()) +              { +                switch(portsi.recMTCtype()) +                { +                  case 0: +                    lvi->setText(DEVCOL_MTCTYPE, "24"); +                  break;   +                  case 1: +                    lvi->setText(DEVCOL_MTCTYPE, "25"); +                  break;   +                  case 2: +                    lvi->setText(DEVCOL_MTCTYPE, "30D"); +                  break;   +                  case 3: +                    lvi->setText(DEVCOL_MTCTYPE, "30N"); +                  break;   +                  default: +                    lvi->setText(DEVCOL_MTCTYPE, "??"); +                  break;   +                }   +              }   +            } +            else +            { +              lvi->_curMTCDet = false; +              lvi->_MTCDet = false; +              lvi->setPixmap(DEVCOL_MTCIN, *dothIcon); +              //lvi->setText(DEVCOL_MTCTYPE, "--"); +            } +                          //lvi->setText(DEVCOL_RID,    QString().setNum(si.idIn()) );              //lvi->setRenameEnabled(DEVCOL_RID, true);              //lvi->setPixmap(DEVCOL_RCLK, si.MCIn() ? *dotIcon : *dothIcon); @@ -748,14 +986,47 @@ void MidiSyncConfig::dlvClicked(int /*button*/, QListViewItem* item, const QPoin                    //  and sync is in fact detected on this port, allow the user to force this port to now be the                    //  current sync in port.                     //if(no != curMidiSyncInPort && si.MCIn() && midiPorts[no].syncInfo().MCSyncDetect()) -                  if(no != curMidiSyncInPort && lvi->_recMC && midiPorts[no].syncInfo().MCSyncDetect()) +                  //if(no != curMidiSyncInPort && lvi->_recMC && midiPorts[no].syncInfo().MCSyncDetect()) +                  if(no != curMidiSyncInPort)                    { -                    curMidiSyncInPort = no; -                    lvi->setPixmap(DEVCOL_IN, *record1_Icon); +                    if(lvi->_recMC && midiPorts[no].syncInfo().MCSyncDetect()) +                    { +                      curMidiSyncInPort = no; +                      lvi->setPixmap(DEVCOL_IN, *record1_Icon); +                    }   +                    if(lvi->_recMTC && midiPorts[no].syncInfo().MTCDetect()) +                    { +                      curMidiSyncInPort = no; +                      lvi->setPixmap(DEVCOL_MTCIN, *record1_Icon); +                    }                      }                      break;              case DEVCOL_TICKIN:                    break; +            case DEVCOL_MMCIN: +                  break; +            case DEVCOL_MTCIN: +                  // If this is not the current midi sync in port, and sync in from this port is enabled, +                  //  and sync is in fact detected on this port, allow the user to force this port to now be the +                  //  current sync in port.  +                  //if(no != curMidiSyncInPort && si.MTCIn() && midiPorts[no].syncInfo().MTCDetect()) +                  //if(no != curMidiSyncInPort && lvi->_recMTC && midiPorts[no].syncInfo().MTCDetect()) +                  if(no != curMidiSyncInPort) +                  { +                    if(lvi->_recMTC && midiPorts[no].syncInfo().MTCDetect()) +                    { +                      curMidiSyncInPort = no; +                      lvi->setPixmap(DEVCOL_MTCIN, *record1_Icon); +                    }   +                    if(lvi->_recMC && midiPorts[no].syncInfo().MCSyncDetect()) +                    { +                      curMidiSyncInPort = no; +                      lvi->setPixmap(DEVCOL_IN, *record1_Icon); +                    }   +                  }   +                  break; +            case DEVCOL_MTCTYPE: +                  break;              case DEVCOL_RID:                    break;              case DEVCOL_RCLK: @@ -828,7 +1099,7 @@ void MidiSyncConfig::dlvDoubleClicked(QListViewItem* item, const QPoint&, int co        {          //int id = lvi->syncInfo().idIn();          int id = lvi->_idIn; -        int newid = QInputDialog::getInteger("Muse: Sync info" , "Enter new id number:", id, 0, 127, 1, &ok, this); +        int newid = QInputDialog::getInteger("Muse: Sync info" , "Enter new id number (127 = all):", id, 0, 127, 1, &ok, this);          if(ok)          {            //lvi->syncInfo().setIdIn(newid); @@ -841,7 +1112,7 @@ void MidiSyncConfig::dlvDoubleClicked(QListViewItem* item, const QPoint&, int co        {          //int id = lvi->syncInfo().idOut();          int id = lvi->_idOut; -        int newid = QInputDialog::getInteger("Muse: Sync info" , "Enter new id number:", id, 0, 127, 1, &ok, this); +        int newid = QInputDialog::getInteger("Muse: Sync info" , "Enter new id number (127 = global):", id, 0, 127, 1, &ok, this);          if(ok)          {            //lvi->syncInfo().setIdOut(newid); diff --git a/muse/muse/widgets/midisyncimpl.h b/muse/muse/widgets/midisyncimpl.h index cbca11d4..afb640f9 100644 --- a/muse/muse/widgets/midisyncimpl.h +++ b/muse/muse/widgets/midisyncimpl.h @@ -75,7 +75,11 @@ class MidiSyncLViewItem : public QListViewItem        //int _port;        bool _inDet;        bool _curDet; +      bool _curMTCDet;        bool _tickDet; +      bool _MMCDet; +      bool _MTCDet; +      int _recMTCtype;        int _idOut;        int _idIn; | 
