summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTim E. Real <termtech@rogers.com>2010-01-31 20:50:25 +0000
committerTim E. Real <termtech@rogers.com>2010-01-31 20:50:25 +0000
commit1e137ce981f9c2b04641c68ead9a2c28859e3b23 (patch)
tree400c2928162c68c086c6f0d4e56e26ea148603ca
parentfda050157888a59f65b14344c5879ab9ca7e764b (diff)
See ChangeLog
-rw-r--r--muse/ChangeLog8
-rw-r--r--muse/muse/audio.cpp237
-rw-r--r--muse/muse/conf.cpp4
-rw-r--r--muse/muse/driver/alsamidi.cpp1
-rw-r--r--muse/muse/event.cpp2
-rw-r--r--muse/muse/sync.cpp108
-rw-r--r--muse/muse/sync.h12
-rw-r--r--muse/muse/widgets/midisync.ui55
-rw-r--r--muse/muse/widgets/midisyncimpl.cpp87
-rw-r--r--muse/muse/widgets/midisyncimpl.h3
10 files changed, 363 insertions, 154 deletions
diff --git a/muse/ChangeLog b/muse/ChangeLog
index 5991b30d..775dd561 100644
--- a/muse/ChangeLog
+++ b/muse/ChangeLog
@@ -1,3 +1,11 @@
+31.01.2010
+ * Fixed: Midi sync in: Should be very solid and 'in time' now, play/stop/continue. (T356)
+ - Re-coded to begin incrementing immediately upon first-clock detection. Forbid MusE to send transport commands
+ while in external sync mode - our sync router handles that. Was causing problems.
+ - Tested OK: Ensoniq ESQ-1 KB (sends clocks ony between start and stop) and Roland TR-505 drums (clocks always running).
+ The measured general timings were quite different, but (thankfully) clocks and events were not.
+ - MusE responds better to the TR-505 than the ESQ-1 does with a direct midi cable connection! (ESQ gains ticks on continue).
+ * Added: Midi sync window: 'Rewind on start' column. (Also a 'Send first clock delay' box - not implemented yet). (T356)
29.01.2010
* Feature: Dummy audio driver: Added global settings for sample rate and period size. (T356)
- The period size affects midi resolution, and the default was just too long. So this was added.
diff --git a/muse/muse/audio.cpp b/muse/muse/audio.cpp
index e8b38904..3e8ce004 100644
--- a/muse/muse/audio.cpp
+++ b/muse/muse/audio.cpp
@@ -779,8 +779,12 @@ void Audio::seek(const Pos& p)
midiSeq->msgSeek(); // handle stuck notes and set
// controller for new position
- //if(genMCSync)
- //{
+
+ // p3.3.31
+ // Don't send if external sync is on. The master, and our sync routing system will take care of that.
+ if(!extSyncFlag.value())
+ {
+
for(int port = 0; port < MIDI_PORTS; ++port)
{
MidiPort* mp = &midiPorts[port];
@@ -816,7 +820,7 @@ void Audio::seek(const Pos& p)
if(isPlaying)
mp->sendContinue();
}
- //}
+ }
/*
if(genMCSync)
@@ -941,43 +945,49 @@ void Audio::startRolling()
state = PLAY;
write(sigFd, "1", 1); // Play
- // Changed by Tim. p3.3.6
- //if (genMMC)
- // midiPorts[txSyncPort].sendSysex(mmcDeferredPlayMsg, sizeof(mmcDeferredPlayMsg));
- //if (genMCSync) {
- // if (curTickPos)
- // midiPorts[txSyncPort].sendContinue();
- // else
- // midiPorts[txSyncPort].sendStart();
- // }
- for(int port = 0; port < MIDI_PORTS; ++port)
+ // p3.3.31
+ // Don't send if external sync is on. The master, and our sync routing system will take care of that.
+ if(!extSyncFlag.value())
{
- MidiPort* mp = &midiPorts[port];
- MidiDevice* dev = mp->device();
- if(!dev)
- continue;
-
- // Shall we check open flags?
- //if(!(dev->rwFlags() & 0x1) || !(dev->openFlags() & 1))
- //if(!(dev->openFlags() & 1))
- // continue;
- MidiSyncInfo& si = mp->syncInfo();
-
- //if(genMMC && si.MMCOut())
- if(si.MMCOut())
- //mp->sendSysex(mmcDeferredPlayMsg, sizeof(mmcDeferredPlayMsg));
- mp->sendMMCDeferredPlay();
-
- //if(genMCSync && si.MCOut())
- if(si.MCOut())
+ // Changed by Tim. p3.3.6
+ //if (genMMC)
+ // midiPorts[txSyncPort].sendSysex(mmcDeferredPlayMsg, sizeof(mmcDeferredPlayMsg));
+ //if (genMCSync) {
+ // if (curTickPos)
+ // midiPorts[txSyncPort].sendContinue();
+ // else
+ // midiPorts[txSyncPort].sendStart();
+ // }
+ for(int port = 0; port < MIDI_PORTS; ++port)
{
- if(curTickPos)
- mp->sendContinue();
- else
- mp->sendStart();
- }
- }
+ MidiPort* mp = &midiPorts[port];
+ MidiDevice* dev = mp->device();
+ if(!dev)
+ continue;
+
+ // Shall we check open flags?
+ //if(!(dev->rwFlags() & 0x1) || !(dev->openFlags() & 1))
+ //if(!(dev->openFlags() & 1))
+ // continue;
+
+ MidiSyncInfo& si = mp->syncInfo();
+
+ //if(genMMC && si.MMCOut())
+ if(si.MMCOut())
+ //mp->sendSysex(mmcDeferredPlayMsg, sizeof(mmcDeferredPlayMsg));
+ mp->sendMMCDeferredPlay();
+
+ //if(genMCSync && si.MCOut())
+ if(si.MCOut())
+ {
+ if(curTickPos)
+ mp->sendContinue();
+ else
+ mp->sendStart();
+ }
+ }
+ }
/*
for(iMidiDevice imd = midiDevices.begin(); imd != midiDevices.end(); ++imd)
@@ -1125,76 +1135,103 @@ void Audio::stopRolling()
}
#endif
- // Changed by Tim. p3.3.6
- //MidiPort* syncPort = &midiPorts[txSyncPort];
- //if (genMMC) {
- // 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();
- // syncPort->sendSysex(mmcStopMsg, sizeof(mmcStopMsg));
- // syncPort->sendSysex(mmcPos, sizeof(mmcPos));
- // }
- //if (genMCSync) { // Midi Clock
- // send STOP and
- // "set song position pointer"
- // syncPort->sendStop();
- // syncPort->sendSongpos(curTickPos * 4 / config.division);
- // }
- for(int port = 0; port < MIDI_PORTS; ++port)
+
+ // p3.3.31
+ // Don't send if external sync is on. The master, and our sync routing system will take care of that.
+ if(!extSyncFlag.value())
{
- MidiPort* mp = &midiPorts[port];
- MidiDevice* dev = mp->device();
- if(!dev)
- continue;
-
- // Shall we check open flags?
- //if(!(dev->rwFlags() & 0x1) || !(dev->openFlags() & 1))
- //if(!(dev->openFlags() & 1))
- // continue;
- MidiSyncInfo& si = mp->syncInfo();
-
- //if(genMMC && si.MMCOut())
- if(si.MMCOut())
+ // Changed by Tim. p3.3.6
+ //MidiPort* syncPort = &midiPorts[txSyncPort];
+ //if (genMMC) {
+ // 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();
+ // syncPort->sendSysex(mmcStopMsg, sizeof(mmcStopMsg));
+ // syncPort->sendSysex(mmcPos, sizeof(mmcPos));
+ // }
+ //if (genMCSync) { // Midi Clock
+ // send STOP and
+ // "set song position pointer"
+ // syncPort->sendStop();
+ // syncPort->sendSongpos(curTickPos * 4 / config.division);
+ // }
+ for(int port = 0; port < MIDI_PORTS; ++port)
{
- //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();
+ MidiPort* mp = &midiPorts[port];
+ MidiDevice* dev = mp->device();
+ if(!dev)
+ continue;
+
+ // Shall we check open flags?
+ //if(!(dev->rwFlags() & 0x1) || !(dev->openFlags() & 1))
+ //if(!(dev->openFlags() & 1))
+ // continue;
- //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
- if(si.MCOut()) // Midi Clock
- {
- // send STOP and
- // "set song position pointer"
- mp->sendStop();
- mp->sendSongpos(curTickPos * 4 / config.division);
+ MidiSyncInfo& si = mp->syncInfo();
+
+ //if(genMMC && si.MMCOut())
+ if(si.MMCOut())
+ {
+ //unsigned char mmcPos[] = {
+ // 0x7f, 0x7f, 0x06, 0x44, 0x06, 0x01,
+ // 0, 0, 0, 0, 0
+ // };
+
+ // p3.3.31
+ /*
+ 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();
+
+ //mp->sendSysex(mmcStopMsg, sizeof(mmcStopMsg));
+ mp->sendMMCStop();
+ //mp->sendSysex(mmcPos, sizeof(mmcPos));
+
+ // P3.3.31
+ // Added check of option send continue not start.
+ // Hmm, is this required? Seems to make other devices unhappy.
+ /*
+ if(!si.sendContNotStart())
+ mp->sendMMCLocate(mtc.h() | (mtcType << 5),
+ mtc.m(), mtc.s(), mtc.f(), mtc.sf());
+ */
+
+ }
+
+ //if(genMCSync && si.MCOut()) // Midi Clock
+ if(si.MCOut()) // Midi Clock
+ {
+ // send STOP and
+ // "set song position pointer"
+ mp->sendStop();
+
+ // P3.3.31
+ // Added check of option send continue not start.
+ // Hmm, is this required? Seems to make other devices unhappy.
+ /*
+ if(!si.sendContNotStart())
+ mp->sendSongpos(curTickPos * 4 / config.division);
+ */
+
+ }
}
}
-
/*
for(iMidiDevice imd = midiDevices.begin(); imd != midiDevices.end(); ++imd)
{
diff --git a/muse/muse/conf.cpp b/muse/muse/conf.cpp
index 54554684..57d6f4f0 100644
--- a/muse/muse/conf.cpp
+++ b/muse/muse/conf.cpp
@@ -661,6 +661,8 @@ void readConfiguration(Xml& xml, bool readOnlySequencer)
xml.parseInt();
else if (tag == "mtctype")
mtcType= xml.parseInt();
+ else if (tag == "sendClockDelay")
+ syncSendFirstClockDelay = xml.parseUInt();
else if (tag == "extSync")
extSyncFlag.setValue(xml.parseInt());
else if (tag == "useJackTransport")
@@ -1098,6 +1100,7 @@ void MusE::writeGlobalConfiguration(int level, Xml& xml) const
xml.nput(level, "<mtcoffset>%02d:%02d:%02d:%02d:%02d</mtcoffset>\n",
mtcOffset.h(), mtcOffset.m(), mtcOffset.s(),
mtcOffset.f(), mtcOffset.sf());
+ //xml.uintTag(level, "sendClockDelay", syncSendFirstClockDelay);
//xml.intTag(level, "useJackTransport", useJackTransport);
//xml.intTag(level, "jackTransportMaster", jackTransportMaster);
extSyncFlag.save(level, xml);
@@ -1208,6 +1211,7 @@ void MusE::writeConfiguration(int level, Xml& xml) const
xml.nput(level, "<mtcoffset>%02d:%02d:%02d:%02d:%02d</mtcoffset>\n",
mtcOffset.h(), mtcOffset.m(), mtcOffset.s(),
mtcOffset.f(), mtcOffset.sf());
+ xml.uintTag(level, "sendClockDelay", syncSendFirstClockDelay);
xml.intTag(level, "useJackTransport", useJackTransport);
xml.intTag(level, "jackTransportMaster", jackTransportMaster);
extSyncFlag.save(level, xml);
diff --git a/muse/muse/driver/alsamidi.cpp b/muse/muse/driver/alsamidi.cpp
index f6483a6b..bbf320da 100644
--- a/muse/muse/driver/alsamidi.cpp
+++ b/muse/muse/driver/alsamidi.cpp
@@ -17,6 +17,7 @@
#include "../audio.h"
#include "mpevent.h"
//#include "sync.h"
+#include "utils.h"
static int alsaSeqFdi = -1;
static int alsaSeqFdo = -1;
diff --git a/muse/muse/event.cpp b/muse/muse/event.cpp
index e0ef9a30..61868f1d 100644
--- a/muse/muse/event.cpp
+++ b/muse/muse/event.cpp
@@ -66,7 +66,7 @@ void EventBase::dump(int n) const
Event Event::clone()
{
// p3.3.31
- printf("Event::clone() this:%p\n", this);
+ //printf("Event::clone() this:%p\n", this);
// p3.3.31
//return Event(ev->clone());
diff --git a/muse/muse/sync.cpp b/muse/muse/sync.cpp
index d9fdc35a..4de2820d 100644
--- a/muse/muse/sync.cpp
+++ b/muse/muse/sync.cpp
@@ -26,8 +26,7 @@
//MidiSyncPort midiSyncPorts[MIDI_PORTS];
int volatile curMidiSyncInPort = -1;
-// P3.3.26
-bool debugSync = true;
+bool debugSync = false;
int mtcType = 1;
MTC mtcOffset;
@@ -49,6 +48,9 @@ static bool mtcSync; // receive complete mtc frame?
// p3.3.28
static bool playPendingFirstClock = false;
+unsigned int syncSendFirstClockDelay = 1; // In milliseconds.
+//static int lastStoppedBeat = 0;
+static unsigned int curExtMidiSyncTick = 0;
// Not used yet.
// static bool mcStart = false;
@@ -90,6 +92,8 @@ MidiSyncInfo::MidiSyncInfo()
_MMCDetect = false;
_MTCDetect = false;
_recMTCtype = 0;
+ _recRewOnStart = true;
+ //_sendContNotStart = false;
_actDetectBits = 0;
for(int i = 0; i < MIDI_CHANNELS; ++i)
{
@@ -122,7 +126,6 @@ MidiSyncInfo& MidiSyncInfo::operator=(const MidiSyncInfo &sp)
_MMCDetect = sp._MMCDetect;
_MTCDetect = sp._MTCDetect;
_recMTCtype = sp._recMTCtype;
- _actDetectBits = sp._actDetectBits;
for(int i = 0; i < MIDI_CHANNELS; ++i)
{
_lastActTime[i] = sp._lastActTime[i];
@@ -148,6 +151,8 @@ MidiSyncInfo& MidiSyncInfo::copyParams(const MidiSyncInfo &sp)
setMCIn(sp._recMC);
_recMMC = sp._recMMC;
_recMTC = sp._recMTC;
+ _recRewOnStart = sp._recRewOnStart;
+ //_sendContNotStart = sp._sendContNotStart;
return *this;
}
@@ -364,12 +369,16 @@ void MidiSyncInfo::read(Xml& xml)
_sendMMC = xml.parseInt();
else if (tag == "sendMTC")
_sendMTC = xml.parseInt();
+ //else if (tag == "sendContNotStart")
+ // _sendContNotStart = xml.parseInt();
else if (tag == "recMC")
_recMC = xml.parseInt();
else if (tag == "recMMC")
_recMMC = xml.parseInt();
else if (tag == "recMTC")
_recMTC = xml.parseInt();
+ else if (tag == "recRewStart")
+ _recRewOnStart = xml.parseInt();
else
xml.unknown("midiSyncInfo");
break;
@@ -393,7 +402,8 @@ void MidiSyncInfo::write(int level, Xml& xml)
// return;
// All defaults? Nothing to write.
- if(_idOut == 127 && _idIn == 127 && !_sendMC && !_sendMMC && !_sendMTC && !_recMC && !_recMMC && !_recMTC)
+ if(_idOut == 127 && _idIn == 127 && !_sendMC && !_sendMMC && !_sendMTC &&
+ /* !_sendContNotStart && */ !_recMC && !_recMMC && !_recMTC && _recRewOnStart)
return;
xml.tag(level++, "midiSyncInfo");
@@ -414,6 +424,8 @@ void MidiSyncInfo::write(int level, Xml& xml)
xml.intTag(level, "sendMMC", true);
if(_sendMTC)
xml.intTag(level, "sendMTC", true);
+ //if(_sendContNotStart)
+ // xml.intTag(level, "sendContNotStart", true);
if(_recMC)
xml.intTag(level, "recMC", true);
@@ -421,6 +433,8 @@ void MidiSyncInfo::write(int level, Xml& xml)
xml.intTag(level, "recMMC", true);
if(_recMTC)
xml.intTag(level, "recMTC", true);
+ if(!_recRewOnStart)
+ xml.intTag(level, "recRewStart", false);
xml.etag(level, "midiSyncInfo");
}
@@ -719,13 +733,15 @@ void MidiSeq::setSongPosition(int port, int midiBeat)
if(!extSyncFlag.value() || !midiPorts[port].syncInfo().MCIn())
return;
- Pos pos((config.division * midiBeat) / 4, true);
-
// Re-transmit song position to other devices if clock out turned on.
for(int p = 0; p < MIDI_PORTS; ++p)
if(p != port && midiPorts[p].syncInfo().MCOut())
midiPorts[p].sendSongpos(midiBeat);
+ curExtMidiSyncTick = (config.division * midiBeat) / 4;
+ //Pos pos((config.division * midiBeat) / 4, true);
+ Pos pos(curExtMidiSyncTick, true);
+
if (!checkAudioDevice()) return;
//audioDevice->seekTransport(pos.frame());
@@ -815,6 +831,9 @@ void MidiSeq::realtimeSystemInput(int port, int c)
if(port != curMidiSyncInPort)
break;
+ // p3.3.31
+ //printf("midi clock:%f\n", curTime());
+
// Re-transmit clock to other devices if clock out turned on.
// Must be careful not to allow more than one clock input at a time.
// Would re-transmit mixture of multiple clocks - confusing receivers.
@@ -834,7 +853,7 @@ void MidiSeq::realtimeSystemInput(int port, int c)
if(!audio->isPlaying())
audioDevice->startTransport();
}
- else
+ //else
// This part will be run on the second and subsequent clocks, after start.
// Can't check audio state, might not be playing yet, we might miss some increments.
//if(audio->isPlaying())
@@ -842,6 +861,7 @@ void MidiSeq::realtimeSystemInput(int port, int c)
{
int div = config.division/24;
midiExtSyncTicks += div;
+ curExtMidiSyncTick += div;
}
//BEGIN : Original code:
@@ -1110,18 +1130,29 @@ void MidiSeq::realtimeSystemInput(int port, int c)
if (debugSync)
printf(" start\n");
+
+ // p3.3.31
+ //printf("midi start:%f\n", curTime());
+
if (1 /* !audio->isPlaying()*/ /*state == IDLE*/) {
if (!checkAudioDevice()) return;
- //audioDevice->seekTransport(0);
- audioDevice->seekTransport(Pos(0, false));
+
+ // p3.3.31
+ // Rew on start option.
+ if(midiPorts[port].syncInfo().recRewOnStart())
+ {
+ curExtMidiSyncTick = 0;
+ //audioDevice->seekTransport(0);
+ audioDevice->seekTransport(Pos(0, false));
+ }
- unsigned curFrame = audio->curFrame();
- if (debugSync)
- printf(" curFrame=%d\n", curFrame);
+ //unsigned curFrame = audio->curFrame();
+ //if (debugSync)
+ // printf(" curFrame=%d\n", curFrame);
alignAllTicks();
- if (debugSync)
- printf(" curFrame: %d curTick: %d tempo: %d\n", curFrame, recTick, tempomap.tempo(0));
+ //if (debugSync)
+ // printf(" curFrame: %d curTick: %d tempo: %d\n", curFrame, recTick, tempomap.tempo(0));
storedtimediffs = 0;
for (int i=0; i<24; i++)
@@ -1135,6 +1166,7 @@ void MidiSeq::realtimeSystemInput(int port, int c)
// p3.3.28
playPendingFirstClock = true;
+ midiExtSyncTicks = 0;
playStateExt = true;
}
break;
@@ -1146,6 +1178,10 @@ void MidiSeq::realtimeSystemInput(int port, int c)
if (debugSync)
printf("realtimeSystemInput continue\n");
+
+ // p3.3.31
+ //printf("continue:%f\n", curTime());
+
if (1 /* !audio->isPlaying() */ /*state == IDLE */) {
//unsigned curFrame = audio->curFrame();
//recTick = tempomap.frame2tick(curFrame); // don't think this will work... (ml)
@@ -1153,25 +1189,45 @@ void MidiSeq::realtimeSystemInput(int port, int c)
// p3.3.28
//audio->msgPlay(true);
+ // p3.3.31
+ // Begin incrementing immediately upon first clock reception.
playPendingFirstClock = true;
playStateExt = true;
}
break;
case 0xfc: // stop
- // Re-transmit stop to other devices if clock out turned on.
- for(int p = 0; p < MIDI_PORTS; ++p)
- if(p != port && midiPorts[p].syncInfo().MCOut())
- midiPorts[p].sendStop();
-
- playPendingFirstClock = false;
+ {
+ // Re-transmit stop to other devices if clock out turned on.
+ for(int p = 0; p < MIDI_PORTS; ++p)
+ if(p != port && midiPorts[p].syncInfo().MCOut())
+ midiPorts[p].sendStop();
+
+ playPendingFirstClock = false;
+
+ //lastStoppedBeat = (audio->tickPos() * 4) / config.division;
+ //curExtMidiSyncTick = (config.division * lastStoppedBeat) / 4;
+
+ if (debugSync)
+ printf("realtimeSystemInput stop\n");
+
+ // p3.3.31
+ //printf("stop:%f\n", curTime());
+
+ if (audio->isPlaying() /*state == PLAY*/) {
+ audio->msgPlay(false);
+ playStateExt = false;
+ }
+
+ // Just in case the process still runs a cycle or two and causes the
+ // audio tick position to increment, reset the incrementer and force
+ // the transport position to what the hardware thinks is the current position.
+ midiExtSyncTicks = 0;
+ //Pos pos((config.division * lastStoppedBeat) / 4, true);
+ Pos pos(curExtMidiSyncTick, true);
+ audioDevice->seekTransport(pos);
+ }
- if (debugSync)
- printf("realtimeSystemInput stop\n");
- if (audio->isPlaying() /*state == PLAY*/) {
- audio->msgPlay(false);
- playStateExt = false;
- }
break;
case 0xfd: // unknown
case 0xfe: // active sensing
diff --git a/muse/muse/sync.h b/muse/muse/sync.h
index 36148ee5..8b164b90 100644
--- a/muse/muse/sync.h
+++ b/muse/muse/sync.h
@@ -34,6 +34,9 @@ class MidiSyncInfo
int _recMTCtype;
+ bool _recRewOnStart;
+ //bool _sendContNotStart;
+
double _lastClkTime;
double _lastTickTime;
double _lastMMCTime;
@@ -82,7 +85,12 @@ class MidiSyncInfo
void setTime();
- bool MCSyncDetect() const { return _clockDetect; }
+ bool recRewOnStart() const { return _recRewOnStart; }
+ void setRecRewOnStart(const bool v) { _recRewOnStart = v; }
+ //bool sendContNotStart() const { return _sendContNotStart; }
+ //void setSendContNotStart(const bool v) { _sendContNotStart = v; }
+
+ bool MCSyncDetect() const { return _clockDetect; }
void trigMCSyncDetect();
bool tickDetect() const { return _tickDetect; }
@@ -126,6 +134,8 @@ extern BValue extSyncFlag;
extern int volatile curMidiSyncInPort;
extern bool volatile useJackTransport;
extern bool volatile jackTransportMaster;
+extern unsigned int syncSendFirstClockDelay; // In milliseconds.
+
#endif
diff --git a/muse/muse/widgets/midisync.ui b/muse/muse/widgets/midisync.ui
index 464d1e21..f9c9a816 100644
--- a/muse/muse/widgets/midisync.ui
+++ b/muse/muse/widgets/midisync.ui
@@ -300,7 +300,7 @@ configuration dialog</comment>
<property name="name">
<cstring>unnamed</cstring>
</property>
- <widget class="QCheckBox" row="0" column="0">
+ <widget class="QCheckBox" row="0" column="0" rowspan="1" colspan="2">
<property name="name">
<cstring>useJackTransportCheckbox</cstring>
</property>
@@ -321,7 +321,7 @@ configuration dialog</comment>
including stop, start and position.</string>
</property>
</widget>
- <widget class="QCheckBox" row="1" column="0">
+ <widget class="QCheckBox" row="1" column="0" rowspan="1" colspan="2">
<property name="name">
<cstring>jackTransportMasterCheckbox</cstring>
</property>
@@ -346,7 +346,7 @@ MusE will try to become master, but other
You can always click here again for Master.</string>
</property>
</widget>
- <widget class="QCheckBox" row="2" column="0">
+ <widget class="QCheckBox" row="2" column="0" rowspan="1" colspan="2">
<property name="name">
<cstring>extSyncCheckbox</cstring>
</property>
@@ -370,7 +370,54 @@ Enabled inputs in the list will
be in effect (RMC, RMMC, RMTC).</string>
</property>
</widget>
- <widget class="QListView" row="3" column="0">
+ <widget class="QLayoutWidget" row="3" column="0">
+ <property name="name">
+ <cstring>syncDelayLayout</cstring>
+ </property>
+ <hbox>
+ <widget class="QSpinBox">
+ <property name="name">
+ <cstring>syncDelaySpinBox</cstring>
+ </property>
+ <property name="suffix">
+ <string>ms</string>
+ </property>
+ <property name="maxValue">
+ <number>60000</number>
+ </property>
+ <property name="minValue">
+ <number>0</number>
+ </property>
+ <property name="lineStep">
+ <number>1</number>
+ </property>
+ <property name="value">
+ <number>1</number>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Send start to first clock delay</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Allows 'slow sync' devices time
+ to synchronize to MusE. This value is the
+ delay from sending start to sending
+ the first clock.</string>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>syncDelayLabel</cstring>
+ </property>
+ <property name="text">
+ <string>Send sync delay</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignLeft</set>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QListView" row="4" column="0">
<property name="name">
<cstring>devicesListView</cstring>
</property>
diff --git a/muse/muse/widgets/midisyncimpl.cpp b/muse/muse/widgets/midisyncimpl.cpp
index 205da2cf..2c5cbb8c 100644
--- a/muse/muse/widgets/midisyncimpl.cpp
+++ b/muse/muse/widgets/midisyncimpl.cpp
@@ -34,10 +34,9 @@
#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_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 };
+enum { DEVCOL_NO = 0, DEVCOL_NAME, DEVCOL_IN, DEVCOL_TICKIN, DEVCOL_MMCIN, DEVCOL_MTCIN, DEVCOL_MTCTYPE,
+ DEVCOL_RID, DEVCOL_RCLK, DEVCOL_RMMC, DEVCOL_RMTC, DEVCOL_RREWSTART,
+ DEVCOL_TID, DEVCOL_TCLK, DEVCOL_TMMC, DEVCOL_TMTC, /* DEVCOL_TREWSTART, */ };
//MidiSyncInfo tmpMidiSyncPorts[MIDI_PORTS];
@@ -67,10 +66,12 @@ void MSyncHeaderTip::maybeTip(const QPoint &pos)
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_RREWSTART: p = QHeader::tr("Receiving start rewinds before playing"); 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;
+ //case DEVCOL_TREWSTART: p = QHeader::tr("Send continue instead of start"); break;
default: return;
}
tip(r, p);
@@ -119,6 +120,9 @@ QString MSyncWhatsThis::text(const QPoint& pos)
case DEVCOL_RMTC:
return QHeader::tr("Accept MTC input, including forward quarter-frame sync and full-frame locate.\n"
"See rmc column for more help.");
+ case DEVCOL_RREWSTART:
+ return QHeader::tr("When start is received, rewind before playing. It may be impossible\n"
+ " to rewind fast enough to synchronize with the external device.");
case DEVCOL_TID:
return QHeader::tr("Transmit id number. 127 = global transmit to all.");
case DEVCOL_TCLK:
@@ -130,6 +134,8 @@ QString MSyncWhatsThis::text(const QPoint& pos)
return QHeader::tr("Send MMC output");
case DEVCOL_TMTC:
return QHeader::tr("Send MTC output");
+ //case DEVCOL_TREWSTART:
+ // return QHeader::tr("When transport is starting, send continue instead of start.\n");
default:
break;
}
@@ -180,6 +186,8 @@ void MidiSyncLViewItem::copyFromSyncInfo(const MidiSyncInfo &sp)
_recMC = sp.MCIn();
_recMMC = sp.MMCIn();
_recMTC = sp.MTCIn();
+ _recRewOnStart = sp.recRewOnStart();
+ //_sendContNotStart = sp.sendContNotStart();
}
//---------------------------------------------------------
@@ -197,6 +205,8 @@ void MidiSyncLViewItem::copyToSyncInfo(MidiSyncInfo &sp)
sp.setMCIn(_recMC);
sp.setMMCIn(_recMMC);
sp.setMTCIn(_recMTC);
+ sp.setRecRewOnStart(_recRewOnStart);
+ //sp.setSendContNotStart(_sendContNotStart);
}
//---------------------------------------------------------
@@ -260,10 +270,12 @@ MidiSyncConfig::MidiSyncConfig(QWidget* parent, const char* name)
devicesListView->addColumn(tr("rmc")); // Receive
devicesListView->addColumn(tr("rmmc")); // Receive
devicesListView->addColumn(tr("rmtc")); // Receive
+ devicesListView->addColumn(tr("rrs")); // Receive
devicesListView->addColumn(tr("tid")); // Transmit
devicesListView->addColumn(tr("tmc")); // Transmit
devicesListView->addColumn(tr("tmmc")); // Transmit
devicesListView->addColumn(tr("tmtc")); // Transmit
+ //devicesListView->addColumn(tr("trs")); // Transmit
devicesListView->setFocusPolicy(NoFocus);
devicesListView->setColumnAlignment(DEVCOL_NO, AlignHCenter);
@@ -276,10 +288,12 @@ MidiSyncConfig::MidiSyncConfig(QWidget* parent, const char* name)
devicesListView->setColumnAlignment(DEVCOL_RCLK, AlignCenter);
devicesListView->setColumnAlignment(DEVCOL_RMMC, AlignCenter);
devicesListView->setColumnAlignment(DEVCOL_RMTC, AlignCenter);
+ devicesListView->setColumnAlignment(DEVCOL_RREWSTART, AlignCenter);
//devicesListView->setColumnAlignment(DEVCOL_TID, AlignCenter);
devicesListView->setColumnAlignment(DEVCOL_TCLK, AlignCenter);
devicesListView->setColumnAlignment(DEVCOL_TMMC, AlignCenter);
devicesListView->setColumnAlignment(DEVCOL_TMTC, AlignCenter);
+ //devicesListView->setColumnAlignment(DEVCOL_TREWSTART, AlignCenter);
devicesListView->header()->setResizeEnabled(false, DEVCOL_NO);
devicesListView->header()->setResizeEnabled(false, DEVCOL_IN);
devicesListView->header()->setResizeEnabled(false, DEVCOL_TICKIN);
@@ -287,9 +301,11 @@ MidiSyncConfig::MidiSyncConfig(QWidget* parent, const char* name)
devicesListView->header()->setResizeEnabled(false, DEVCOL_RCLK);
devicesListView->header()->setResizeEnabled(false, DEVCOL_RMMC);
devicesListView->header()->setResizeEnabled(false, DEVCOL_RMTC);
+ devicesListView->header()->setResizeEnabled(false, DEVCOL_RMTC);
+ devicesListView->header()->setResizeEnabled(false, DEVCOL_RREWSTART);
devicesListView->header()->setResizeEnabled(false, DEVCOL_TCLK);
devicesListView->header()->setResizeEnabled(false, DEVCOL_TMMC);
- devicesListView->header()->setResizeEnabled(false, DEVCOL_TMTC);
+ //devicesListView->header()->setResizeEnabled(false, DEVCOL_TREWSTART);
//devicesListView->setResizeMode(QListView::LastColumn);
devicesListView->setResizeMode(QListView::NoColumn);
@@ -321,7 +337,7 @@ MidiSyncConfig::MidiSyncConfig(QWidget* parent, const char* name)
connect(useJackTransportCheckbox, SIGNAL(clicked()), SLOT(syncChanged()));
connect(jackTransportMasterCheckbox, SIGNAL(clicked()), SLOT(syncChanged()));
connect(&extSyncFlag, SIGNAL(valueChanged(bool)), SLOT(extSyncChanged(bool)));
-
+ connect(syncDelaySpinBox, SIGNAL(valueChanged(int)), SLOT(syncChanged()));
// Done in show().
//connect(song, SIGNAL(songChanged(int)), SLOT(songChanged(int)));
@@ -359,10 +375,13 @@ void MidiSyncConfig::songChanged(int flags)
extSyncCheckbox->blockSignals(true);
useJackTransportCheckbox->blockSignals(true);
jackTransportMasterCheckbox->blockSignals(true);
+ syncDelaySpinBox->blockSignals(true);
extSyncCheckbox->setChecked(extSyncFlag.value());
useJackTransportCheckbox->setChecked(useJackTransport);
jackTransportMasterCheckbox->setChecked(jackTransportMaster);
//jackTransportMasterCheckbox->setEnabled(useJackTransport);
+ syncDelaySpinBox->setValue(syncSendFirstClockDelay);
+ syncDelaySpinBox->blockSignals(false);
jackTransportMasterCheckbox->blockSignals(false);
useJackTransportCheckbox->blockSignals(false);
extSyncCheckbox->blockSignals(false);
@@ -701,6 +720,8 @@ void MidiSyncConfig::apply()
// genMCSync = mcSync->isChecked();
// genMMC = midiMachineControl->isChecked();
+ syncSendFirstClockDelay = syncDelaySpinBox->value();
+
mtcType = mtcSyncType->currentItem();
//extSyncFlag.setValue(syncMode->id(syncMode->selected()));
//extSyncFlag.blockSignals(true);
@@ -763,6 +784,16 @@ void MidiSyncConfig::updateSyncInfoLV()
{
MidiPort* port = &midiPorts[i];
MidiDevice* dev = port->device();
+ // p3.3.31
+ // Don't show if it is a synthesizer device.
+ // Hmm, some synths might support transport commands or even sync?
+ // If anything, the DSSI or VST synths just might...
+ // TODO: Must test to see if it screws any of them up, especially clock out.
+ // Also, if we do this, we must prevent such messages from reaching
+ // those ports at several other places in the code.
+ //if(dev && dev->isSynti())
+ // continue;
+
QString s;
s.setNum(i+1);
MidiSyncLViewItem* lvi = new MidiSyncLViewItem(devicesListView);
@@ -899,16 +930,18 @@ void MidiSyncConfig::updateSyncInfoLV()
lvi->setPixmap(DEVCOL_RCLK, lvi->_recMC ? *dotIcon : *dothIcon);
lvi->setPixmap(DEVCOL_RMMC, lvi->_recMMC ? *dotIcon : *dothIcon);
lvi->setPixmap(DEVCOL_RMTC, lvi->_recMTC ? *dotIcon : *dothIcon);
+ lvi->setPixmap(DEVCOL_RREWSTART, lvi->_recRewOnStart ? *dotIcon : *dothIcon);
//lvi->setText(DEVCOL_TID, QString().setNum(si.idOut()) );
//lvi->setRenameEnabled(DEVCOL_TID, true);
//lvi->setPixmap(DEVCOL_TCLK, si.MCOut() ? *dotIcon : *dothIcon);
//lvi->setPixmap(DEVCOL_TMMC, si.MMCOut() ? *dotIcon : *dothIcon);
//lvi->setPixmap(DEVCOL_TMTC, si.MTCOut() ? *dotIcon : *dothIcon);
- lvi->setText(DEVCOL_TID, QString().setNum(lvi->_idOut) );
- lvi->setPixmap(DEVCOL_TCLK, lvi->_sendMC ? *dotIcon : *dothIcon);
- lvi->setPixmap(DEVCOL_TMMC, lvi->_sendMMC ? *dotIcon : *dothIcon);
- lvi->setPixmap(DEVCOL_TMTC, lvi->_sendMTC ? *dotIcon : *dothIcon);
+ lvi->setText(DEVCOL_TID, QString().setNum(lvi->_idOut) );
+ lvi->setPixmap(DEVCOL_TCLK, lvi->_sendMC ? *dotIcon : *dothIcon);
+ lvi->setPixmap(DEVCOL_TMMC, lvi->_sendMMC ? *dotIcon : *dothIcon);
+ lvi->setPixmap(DEVCOL_TMTC, lvi->_sendMTC ? *dotIcon : *dothIcon);
+ //lvi->setPixmap(DEVCOL_TREWSTART, lvi->_sendContNotStart ? *dotIcon : *dothIcon);
devicesListView->insertItem(lvi);
}
@@ -1050,6 +1083,11 @@ void MidiSyncConfig::dlvClicked(int /*button*/, QListViewItem* item, const QPoin
lvi->setPixmap(DEVCOL_RMTC, lvi->_recMTC ? *dotIcon : *dothIcon);
setDirty();
break;
+ case DEVCOL_RREWSTART:
+ lvi->_recRewOnStart = (lvi->_recRewOnStart ? false : true);
+ lvi->setPixmap(DEVCOL_RREWSTART, lvi->_recRewOnStart ? *dotIcon : *dothIcon);
+ setDirty();
+ break;
case DEVCOL_TID:
break;
case DEVCOL_TCLK:
@@ -1073,6 +1111,11 @@ void MidiSyncConfig::dlvClicked(int /*button*/, QListViewItem* item, const QPoin
lvi->setPixmap(DEVCOL_TMTC, lvi->_sendMTC ? *dotIcon : *dothIcon);
setDirty();
break;
+ //case DEVCOL_TREWSTART:
+ // lvi->_sendContNotStart = (lvi->_sendContNotStart ? false : true);
+ // lvi->setPixmap(DEVCOL_TREWSTART, lvi->_sendContNotStart ? *dotIcon : *dothIcon);
+ // setDirty();
+ // break;
}
//songChanged(-1);
}
@@ -1097,27 +1140,27 @@ void MidiSyncConfig::dlvDoubleClicked(QListViewItem* item, const QPoint&, int co
bool ok = false;
if(col == DEVCOL_RID)
{
- //int id = lvi->syncInfo().idIn();
- int id = lvi->_idIn;
- int newid = QInputDialog::getInteger("Muse: Sync info" , "Enter new id number (127 = all):", id, 0, 127, 1, &ok, this);
+ //int val = lvi->syncInfo().idIn();
+ int val = lvi->_idIn;
+ int newval = QInputDialog::getInteger("Muse: Sync info" , "Enter new id number (127 = all):", val, 0, 127, 1, &ok, this);
if(ok)
{
- //lvi->syncInfo().setIdIn(newid);
- lvi->_idIn = newid;
- lvi->setText(DEVCOL_RID, QString().setNum(newid));
+ //lvi->syncInfo().setIdIn(newval);
+ lvi->_idIn = newval;
+ lvi->setText(DEVCOL_RID, QString().setNum(newval));
}
}
else
if(col == DEVCOL_TID)
{
- //int id = lvi->syncInfo().idOut();
- int id = lvi->_idOut;
- int newid = QInputDialog::getInteger("Muse: Sync info" , "Enter new id number (127 = global):", id, 0, 127, 1, &ok, this);
+ //int val = lvi->syncInfo().idOut();
+ int val = lvi->_idOut;
+ int newval = QInputDialog::getInteger("Muse: Sync info" , "Enter new id number (127 = global):", val, 0, 127, 1, &ok, this);
if(ok)
{
- //lvi->syncInfo().setIdOut(newid);
- lvi->_idOut = newid;
- lvi->setText(DEVCOL_TID, QString().setNum(newid));
+ //lvi->syncInfo().setIdOut(newval);
+ lvi->_idOut = newval;
+ lvi->setText(DEVCOL_TID, QString().setNum(newval));
}
}
diff --git a/muse/muse/widgets/midisyncimpl.h b/muse/muse/widgets/midisyncimpl.h
index afb640f9..63c041e5 100644
--- a/muse/muse/widgets/midisyncimpl.h
+++ b/muse/muse/widgets/midisyncimpl.h
@@ -91,6 +91,9 @@ class MidiSyncLViewItem : public QListViewItem
bool _recMMC;
bool _recMTC;
+ bool _recRewOnStart;
+ //bool _sendContNotStart;
+
int port() const { return _port; }
void setPort(int port);
//MidiDevice* device() const { return _device; }