diff options
Diffstat (limited to 'attic/muse_qt4_evolution/muse/sync.cpp')
-rw-r--r-- | attic/muse_qt4_evolution/muse/sync.cpp | 499 |
1 files changed, 499 insertions, 0 deletions
diff --git a/attic/muse_qt4_evolution/muse/sync.cpp b/attic/muse_qt4_evolution/muse/sync.cpp new file mode 100644 index 00000000..c4cb30fc --- /dev/null +++ b/attic/muse_qt4_evolution/muse/sync.cpp @@ -0,0 +1,499 @@ +//============================================================================= +// MusE +// Linux Music Editor +// $Id:$ +// +// Copyright (C) 2002-2006 by Werner Schweer and others +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +//============================================================================= + +#include "sync.h" +#include "song.h" +#include "widgets/utils.h" +#include "globals.h" +#include "audio.h" +#include "audiodev.h" +#include "gconfig.h" +#include "al/tempo.h" +#include "al/al.h" + +int rxSyncPort = -1; // receive from all ports +int txSyncPort = 1; + +bool debugSync = false; +MTC mtcOffset; +bool extSyncFlag = false; +bool genMTCSync = false; // output MTC Sync +bool genMCSync = false; // output MidiClock Sync +bool genMMC = false; // output Midi Machine Control +bool acceptMTC = false; +bool acceptMC = true; +bool acceptMMC = true; + +static MTC mtcCurTime; +// static int mtcState; // 0-7 next expected quarter message +// static bool mtcValid; +// static int mtcLost; +// static bool mtcSync; // receive complete mtc frame? + +//static bool mcStart = false; +//static int mcStartTick; + +enum { + MMC_STOP = 1, + MMC_PLAY = 2, + MMC_DEFERRED_PLAY = 3, + MMC_FAST_FORWARD = 4, + MMC_REWIND = 5, + MMC_RECORD_STROBE = 6, // Punch In + MMC_RECORD_EXIT = 7, // Punch Out + MMC_PAUSE = 9, + MMC_RESET = 13, + MMC_GOTO = 0x44 + }; + +#if 0 +//--------------------------------------------------------- +// mmcInput +// Midi Machine Control Input received +//--------------------------------------------------------- + +void MidiSeq::mmcInput(int id, int cmd, const Pos& pos) + { +#if 0 + int rxDeviceId = 127; + + if (!extSyncFlag || !acceptMMC || (id != 127 && id != rxDeviceId)) + return; + + if (debugMsg) + printf("mmcInput: id %d cmd %02x %02x\n", id, cmd, cmd); + + switch (cmd) { + case MMC_STOP: + if (debugSync) + printf(" MMC: STOP\n"); + if (audio->isPlaying()) + audioDriver->stopTransport(); + else + // reset REC + audio->sendMsgToGui(MSG_STOP); + break; + case MMC_PLAY: + case MMC_DEFERRED_PLAY: + audioDriver->startTransport(); + break; + case MMC_FAST_FORWARD: + printf("MMC: FF not implemented\n"); + break; + case MMC_REWIND: + printf("MMC: REWIND not implemented\n"); + break; + case MMC_RECORD_STROBE: + printf("MMC: REC STROBE not implemented\n"); + break; + case MMC_RECORD_EXIT: + printf("MMC: REC EXIT not implemented\n"); + break; + case MMC_PAUSE: + audio->sendMsgToGui(MSG_RECORD); + break; + case MMC_RESET: + printf("MMC: RESET not implemented\n"); + break; + + case MMC_GOTO: + audioDriver->seekTransport(pos.frame()); + break; + + default: + printf("MMC id %x cmd %x, unknown\n", id, cmd); + break; + } +#endif + } + +//--------------------------------------------------------- +// mtcInputQuarter +// process Quarter Frame Message +//--------------------------------------------------------- + +void MidiSeq::mtcInputQuarter(int, unsigned char c) + { +#if 0 + static int hour, min, sec, frame; + + if (!extSyncFlag) + return; + + int valL = c & 0xf; + int valH = valL << 4; + + int _state = (c & 0x70) >> 4; + if (mtcState != _state) + mtcLost += _state - mtcState; + mtcState = _state + 1; + + switch(_state) { + case 7: + hour = (hour & 0x0f) | valH; + break; + case 6: + hour = (hour & 0xf0) | valL; + break; + case 5: + min = (min & 0x0f) | valH; + break; + case 4: + min = (min & 0xf0) | valL; + break; + case 3: + sec = (sec & 0x0f) | valH; + break; + case 2: + sec = (sec & 0xf0) | valL; + break; + case 1: + frame = (frame & 0x0f) | valH; + break; + case 0: frame = (frame & 0xf0) | valL; + break; + } + frame &= 0x1f; // 0-29 + sec &= 0x3f; // 0-59 + min &= 0x3f; // 0-59 + hour &= 0x1f; + + if (mtcState == 8) { + mtcValid = (mtcLost == 0); + mtcState = 0; + mtcLost = 0; + if (mtcValid) { + mtcCurTime.set(hour, min, sec, frame); + mtcSyncMsg(mtcCurTime, !mtcSync); + mtcSync = true; + } + } + else if (mtcValid && (mtcLost == 0)) { + mtcCurTime.incQuarter(); + mtcSyncMsg(mtcCurTime, false); + } +#endif + } + +//--------------------------------------------------------- +// mtcInputFull +// process Frame Message +//--------------------------------------------------------- + +void MidiSeq::mtcInputFull(const unsigned char* p, int n) + { +#if 0 + if (debugSync) + printf("mtcInputFull\n"); + if (!extSyncFlag) + return; + + if (p[3] != 1) { + if (p[3] != 2) { // silently ignore user bits + printf("unknown mtc msg subtype 0x%02x\n", p[3]); + dump(p, n); + } + return; + } + int hour = p[4]; + int min = p[5]; + int sec = p[6]; + int frame = p[7]; + + frame &= 0x1f; // 0-29 + sec &= 0x3f; // 0-59 + min &= 0x3f; // 0-59 +// int type = (hour >> 5) & 3; + hour &= 0x1f; + + mtcCurTime.set(hour, min, sec, frame); + mtcState = 0; + mtcValid = true; + mtcLost = 0; +#endif + } + +//--------------------------------------------------------- +// nonRealtimeSystemSysex +//--------------------------------------------------------- + +void MidiSeq::nonRealtimeSystemSysex(const unsigned char* p, int n) + { +#if 0 +// int chan = p[2]; + switch(p[3]) { + case 4: + printf("NRT Setup\n"); + break; + default: + printf("unknown NRT Msg 0x%02x\n", p[3]); + dump(p, n); + break; + } +#endif + } + +//--------------------------------------------------------- +// setSongPosition +// MidiBeat is a 14 Bit value. Each MidiBeat spans +// 6 MIDI Clocks. Inother words, each MIDI Beat is a +// 16th note (since there are 24 MIDI Clocks in a +// quarter note). +//--------------------------------------------------------- + +void MidiSeq::setSongPosition(int port, int midiBeat) + { +#if 0 + if (midiInputTrace) + printf("set song position port:%d %d\n", port, midiBeat); + if (!extSyncFlag) + return; + Pos pos((config.division * midiBeat) / 4, AL::TICKS); + audioDriver->seekTransport(pos.frame()); + if (debugSync) + printf("setSongPosition %d\n", pos.tick()); +#endif + } + +//--------------------------------------------------------- +// realtimeSystemInput +// real time message received +//--------------------------------------------------------- + +void MidiSeq::realtimeSystemInput(int port, int c) + { +#if 0 + if (midiInputTrace) + printf("realtimeSystemInput port:%d 0x%x\n", port+1, c); + + if (midiInputTrace && (rxSyncPort != port) && rxSyncPort != -1) { + if (debugSync) + printf("rxSyncPort configured as %d; received sync from port %d\n", + rxSyncPort, port); + return; + } + if (!extSyncFlag) + return; + switch(c) { + case 0xf8: // midi clock (24 ticks / quarter note) + { + 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; + } + } + processMidiClock(); + + // Compare w audio if playing: + if (audio->isPlaying() /*state == PLAY*/) { + //BEGIN standard setup: + recTick += config.division / 24; // The one we're syncing to + int tempo = AL::tempomap.tempo(0); + unsigned curFrame = audio->pos().frame(); + double songtick = (double(curFrame)/double(AL::sampleRate)) * config.division * 1000000.0 / double(tempo); + double scale = tdiff0/averagetimediff; + double tickdiff = songtick - ((double) recTick - 24 + scale*24.0); + + //END standard setup + if (debugSync) { + // + // Create debug values for printing out which beat we're at, etc etc... yaddayadda... + // + 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", songtick, recTick, tickdiff, song_beat, sync_beat, scale); + } + //if ((mclock2 !=0.0) && (tdiff1 > 0.0) && tickdiff != 0.0 && lastTempo != 0) { + if ((mclock2 !=0.0) && (tdiff1 > 0.0) && fabs(tickdiff) > 2.0 && lastTempo != 0) { + // Interpolate: + double tickdiff1 = songtick1 - recTick1; + double tickdiff2 = songtick2 - recTick2; + //double newtickdiff = tickdiff/3.0 + tickdiff1/5.0 + tickdiff2/7.0; //2 min 15 sec, 120BPM, -p 512 jackd + //double newtickdiff = tickdiff/4.0 + tickdiff1/4.0 + tickdiff2/4.0; // Not long... :-P + //double newtickdiff = tickdiff/5.0 + tickdiff1/8.0 + tickdiff2/12.0; //3,5 mins on 120BPM, -p 512 jackd + //double newtickdiff = tickdiff/7.0 + tickdiff1/8.0 + tickdiff2/9.0; //2 min 15 sec, 120BPM, -p 512 jackd + //double newtickdiff = tickdiff/5.0 + tickdiff1/8.0 + tickdiff2/16.0; //3,5 mins on 120BPM, -p 512 jackd + double newtickdiff = tickdiff/5.0 + tickdiff1/16.0 + tickdiff2/24.0; //5 mins 30 secs on 116BPM, -p 512 jackd + //double newtickdiff = tickdiff/5.0 + tickdiff1/23.0 + tickdiff2/31.0; //5 mins on 116BPM, -p 512 jackd + //double newtickdiff = tickdiff + tickdiff1/8.0 + tickdiff2/16.0; // Not long... + + if (newtickdiff != 0.0) { + int newTempo = AL::tempomap.tempo(0); + //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)); + AL::tempomap.setTempo(0,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) { +//TODO3 midiPorts[port].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 = AL::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)); + AL::tempomap.setTempo(0, newTempo); + } + } + mclock2 = mclock1; + mclock1 = mclock0; + } + break; + case 0xf9: // midi tick (every 10 msec) + if (mcStart) { + song->setPos(0, mcStartTick); + mcStart = false; + return; + } + break; + case 0xfa: // start + if (debugSync) + printf(" start\n"); + if (!audio->isPlaying() /*state == IDLE*/) { + //seek(0); + audioDriver->seekTransport(0); + unsigned curFrame = audioDriver->framePos(); + recTick = recTick1 = recTick2 = 0; + mclock1 = 0.0; mclock2 = 0.0; + songtick1 = songtick2 = 0; + if (debugSync) + printf(" curFrame: %d curTick: %d tempo: %d\n", curFrame, recTick, AL::tempomap.tempo(0)); + + //startPlay(); + storedtimediffs = 0; + for (int i=0; i<24; i++) + timediff[i] = 0.0; + audio->msgPlay(true); + } + break; + case 0xfb: // continue + if (debugSync) + printf(" continue\n"); + if (!audio->isPlaying() /*state == IDLE */) { + unsigned curFrame = audioDriver->framePos(); + recTick = AL::tempomap.frame2tick(curFrame); // don't think this will work... (ml) + audio->msgPlay(true); + } + break; + case 0xfc: // stop + if (debugSync) + printf(" stop\n"); + if (audio->isPlaying() /*state == PLAY*/) + audio->msgPlay(false); + break; + case 0xfd: // unknown + case 0xfe: // active sensing + case 0xff: // system reset + break; + } +#endif + + } + +//--------------------------------------------------------- +// mtcSyncMsg +// process received mtc Sync +// seekFlag - first complete mtc frame received after +// start +//--------------------------------------------------------- + +void MidiSeq::mtcSyncMsg(const MTC& /*mtc*/, bool /*seekFlag*/) + { +#if 0 + double time = mtc.time(); + if (debugSync) + printf("mtcSyncMsg: time %f\n", time); + + if (seekFlag && state == START_PLAY) { +// int tick = tempomap.time2tick(time); + state = PLAY; + sendMsgToGui(MSG_PLAY); + return; + } + // double curT = curTime(); + + if (tempoSN != tempomap.tempoSN()) { + double cpos = tempomap.tick2time(_midiTick, 0); + samplePosStart = samplePos - lrint(cpos * sampleRate); + rtcTickStart = rtcTick - lrint(cpos * realRtcTicks); + tempoSN = tempomap.tempoSN(); + } + + // + // diff is the time in sec MusE is out of sync + // + double diff = time - (double(samplePosStart)/double(sampleRate)); + if (debugSync) + printf(" state %d diff %f\n", mtcState, diff); +#endif + } +#endif + |