summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--muse/ChangeLog7
-rw-r--r--muse/muse/audio.cpp44
-rw-r--r--muse/muse/driver/alsamidi.cpp5
-rw-r--r--muse/muse/midi.cpp24
-rw-r--r--muse/muse/midi.h11
-rw-r--r--muse/muse/mididev.cpp75
-rw-r--r--muse/muse/midiport.cpp61
-rw-r--r--muse/muse/midiport.h5
-rw-r--r--muse/muse/midiseq.cpp1
-rw-r--r--muse/muse/midiseq.h11
-rw-r--r--muse/muse/mtc.cpp21
-rw-r--r--muse/muse/mtc.h6
-rw-r--r--muse/muse/sync.cpp369
-rw-r--r--muse/muse/sync.h20
-rw-r--r--muse/muse/widgets/midisyncimpl.cpp313
-rw-r--r--muse/muse/widgets/midisyncimpl.h4
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;