diff options
-rw-r--r-- | muse/ChangeLog | 8 | ||||
-rw-r--r-- | muse/muse/audio.cpp | 237 | ||||
-rw-r--r-- | muse/muse/conf.cpp | 4 | ||||
-rw-r--r-- | muse/muse/driver/alsamidi.cpp | 1 | ||||
-rw-r--r-- | muse/muse/event.cpp | 2 | ||||
-rw-r--r-- | muse/muse/sync.cpp | 108 | ||||
-rw-r--r-- | muse/muse/sync.h | 12 | ||||
-rw-r--r-- | muse/muse/widgets/midisync.ui | 55 | ||||
-rw-r--r-- | muse/muse/widgets/midisyncimpl.cpp | 87 | ||||
-rw-r--r-- | muse/muse/widgets/midisyncimpl.h | 3 |
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; } |