1 //=========================================================
2 //  MusE
3 //  Linux Music Editor
4 //  $Id: sync.cpp,v 1.6.2.12 2009/06/20 22:20:41 terminator356 Exp $
5 //
6 //  (C) Copyright 2003 Werner Schweer (ws@seh.de)
7 //  (C) Copyright 2016 Tim E. Real (terminator356 on sourceforge.net)
8 //
9 //  This program is free software; you can redistribute it and/or
10 //  modify it under the terms of the GNU General Public License
11 //  as published by the Free Software Foundation; version 2 of
12 //  the License, or (at your option) any later version.
13 //
14 //  This program is distributed in the hope that it will be useful,
15 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
16 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 //  GNU General Public License for more details.
18 //
19 //  You should have received a copy of the GNU General Public License
20 //  along with this program; if not, write to the Free Software
21 //  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
22 //
23 //=========================================================
24 
25 #include <stdlib.h>
26 #include "muse_math.h"
27 
28 #include "sync.h"
29 #include "song.h"
30 #include "utils.h"
31 #include "midiport.h"
32 #include "mididev.h"
33 #include "globals.h"
34 #include "midiseq.h"
35 #include "audio.h"
36 #include "audiodev.h"
37 #include "gconfig.h"
38 #include "xml.h"
39 #include "midi_consts.h"
40 #include "large_int.h"
41 
42 namespace MusEGlobal {
43 
44 bool debugSync = false;
45 
46 int mtcType     = 1;
47 MusECore::MTC mtcOffset;
48 bool extSyncFlag = false;       // false - MASTER, true - SLAVE
49 bool timebaseMasterState = false;
50 // Hack when loading songs to force master.
51 bool timebaseMasterForceFlag = false;
52 
53 static MusECore::MTC mtcCurTime;
54 static int mtcState;    // 0-7 next expected quarter message
55 static bool mtcValid;
56 static int mtcLost;
57 static bool mtcSync;    // receive complete mtc frame?
58 
59 unsigned int syncSendFirstClockDelay = 1; // In milliseconds.
60 unsigned int volatile curExtMidiSyncTick = 0;
61 unsigned int volatile lastExtMidiSyncTick = 0;
62 unsigned int volatile curExtMidiSyncFrame = 0;
63 unsigned int volatile lastExtMidiSyncFrame = 0;
64 MusECore::MidiSyncInfo::SyncRecFilterPresetType syncRecFilterPreset = MusECore::MidiSyncInfo::SMALL;
65 double syncRecTempoValQuant = 1.0;
66 
67 MusECore::MidiSyncContainer midiSyncContainer;
68 
69 // Not used yet. DELETETHIS?
70 // static bool mcStart = false;
71 // static int mcStartTick;
72 
73 // From the "Introduction to the Volatile Keyword" at Embedded dot com
74 /* A variable should be declared volatile whenever its value could change unexpectedly.
75  ... <such as> global variables within a multi-threaded application
76  ... So all shared global variables should be declared volatile */
77 unsigned int volatile midiExtSyncTicks = 0;
78 
79 } // namespace MusEGlobal
80 
81 namespace MusECore {
82 
83 //---------------------------------------------------------
84 //  MidiSyncInfo
85 //---------------------------------------------------------
86 
MidiSyncInfo()87 MidiSyncInfo::MidiSyncInfo()
88 {
89   _port          = -1;
90   _idOut         = 127;
91   _idIn          = 127;
92   _sendMC        = false;
93   _sendMRT       = false;
94   _sendMMC       = false;
95   _sendMTC       = false;
96   _recMC         = false;
97   _recMRT        = false;
98   _recMMC        = false;
99   _recMTC        = false;
100 
101   _lastClkTime   = 0;
102   _lastTickTime  = 0;
103   _lastMRTTime   = 0;
104   _lastMMCTime   = 0;
105   _lastMTCTime   = 0;
106   _clockTrig     = false;
107   _tickTrig      = false;
108   _MRTTrig       = false;
109   _MMCTrig       = false;
110   _MTCTrig       = false;
111   _clockDetect   = false;
112   _tickDetect    = false;
113   _MRTDetect     = false;
114   _MMCDetect     = false;
115   _MTCDetect     = false;
116   _recMTCtype    = 0;
117   _recRewOnStart  = true;
118   _actDetectBits = 0;
119   for(int i = 0; i < MusECore::MUSE_MIDI_CHANNELS; ++i)
120   {
121     _lastActTime[i] = 0.0;
122     _actTrig[i]     = false;
123     _actDetect[i]   = false;
124   }
125 }
126 
127 //---------------------------------------------------------
128 //   operator =
129 //---------------------------------------------------------
130 
operator =(const MidiSyncInfo & sp)131 MidiSyncInfo& MidiSyncInfo::operator=(const MidiSyncInfo &sp)
132 {
133   copyParams(sp);
134 
135   _lastClkTime   = sp._lastClkTime;
136   _lastTickTime  = sp._lastTickTime;
137   _lastMRTTime   = sp._lastMRTTime;
138   _lastMMCTime   = sp._lastMMCTime;
139   _lastMTCTime   = sp._lastMTCTime;
140   _clockTrig     = sp._clockTrig;
141   _tickTrig      = sp._tickTrig;
142   _MRTTrig       = sp._MRTTrig;
143   _MMCTrig       = sp._MMCTrig;
144   _MTCTrig       = sp._MTCTrig;
145   _clockDetect   = sp._clockDetect;
146   _tickDetect    = sp._tickDetect;
147   _MRTDetect     = sp._MRTDetect;
148   _MMCDetect     = sp._MMCDetect;
149   _MTCDetect     = sp._MTCDetect;
150   _recMTCtype    = sp._recMTCtype;
151   for(int i = 0; i < MusECore::MUSE_MIDI_CHANNELS; ++i)
152   {
153     _lastActTime[i] = sp._lastActTime[i];
154     _actTrig[i]     = sp._actTrig[i];
155     _actDetect[i]   = sp._actDetect[i];
156   }
157   return *this;
158 }
159 
160 //---------------------------------------------------------
161 //   copyParams
162 //---------------------------------------------------------
163 
copyParams(const MidiSyncInfo & sp)164 MidiSyncInfo& MidiSyncInfo::copyParams(const MidiSyncInfo &sp)
165 {
166   _idOut         = sp._idOut;
167   _idIn          = sp._idIn;
168   _sendMC        = sp._sendMC;
169   _sendMRT       = sp._sendMRT;
170   _sendMMC       = sp._sendMMC;
171   _sendMTC       = sp._sendMTC;
172   setMCIn(sp._recMC);
173   _recMRT        = sp._recMRT;
174   _recMMC        = sp._recMMC;
175   _recMTC        = sp._recMTC;
176   _recRewOnStart = sp._recRewOnStart;
177   return *this;
178 }
179 
180 //---------------------------------------------------------
181 //  setTime
182 //---------------------------------------------------------
183 
setTime()184 void MidiSyncInfo::setTime()
185 {
186   // Note: CurTime() makes a system call to gettimeofday(),
187   //  which apparently can be slow in some cases. So I avoid calling this function
188   //  too frequently by calling it (at the heartbeat rate) in Song::beat().  T356
189   uint64_t t = curTimeUS();
190 
191   if(_clockTrig)
192   {
193     _clockTrig = false;
194     _lastClkTime = t;
195   }
196   else
197   if(_clockDetect && (t - _lastClkTime >= 1000000UL)) // Set detect indicator timeout to about 1 second.
198   {
199     _clockDetect = false;
200   }
201 
202   if(_tickTrig)
203   {
204     _tickTrig = false;
205     _lastTickTime = t;
206   }
207   else
208 //   if(_tickDetect && (t - _lastTickTime) >= 1.0) // Set detect indicator timeout to about 1 second.
209   if(_tickDetect && (t - _lastTickTime) >= 1000000UL) // Set detect indicator timeout to about 1 second.
210     _tickDetect = false;
211 
212   if(_MRTTrig)
213   {
214     _MRTTrig = false;
215     _lastMRTTime = t;
216   }
217   else
218 //   if(_MRTDetect && (t - _lastMRTTime) >= 1.0) // Set detect indicator timeout to about 1 second.
219   if(_MRTDetect && (t - _lastMRTTime) >= 1000000UL) // Set detect indicator timeout to about 1 second.
220   {
221     _MRTDetect = false;
222   }
223 
224   if(_MMCTrig)
225   {
226     _MMCTrig = false;
227     _lastMMCTime = t;
228   }
229   else
230 //   if(_MMCDetect && (t - _lastMMCTime) >= 1.0) // Set detect indicator timeout to about 1 second.
231   if(_MMCDetect && (t - _lastMMCTime) >= 1000000UL) // Set detect indicator timeout to about 1 second.
232   {
233     _MMCDetect = false;
234   }
235 
236   if(_MTCTrig)
237   {
238     _MTCTrig = false;
239     _lastMTCTime = t;
240   }
241   else
242 //   if(_MTCDetect && (t - _lastMTCTime) >= 1.0) // Set detect indicator timeout to about 1 second.
243   if(_MTCDetect && (t - _lastMTCTime) >= 1000000UL) // Set detect indicator timeout to about 1 second.
244   {
245     _MTCDetect = false;
246   }
247 
248   for(int i = 0; i < MusECore::MUSE_MIDI_CHANNELS; i++)
249   {
250     if(_actTrig[i])
251     {
252       _actTrig[i] = false;
253       _lastActTime[i] = t;
254     }
255     else
256 //     if(_actDetect[i] && (t - _lastActTime[i]) >= 1.0) // Set detect indicator timeout to about 1 second.
257     if(_actDetect[i] && (t - _lastActTime[i]) >= 1000000UL) // Set detect indicator timeout to about 1 second.
258     {
259       _actDetect[i] = false;
260       _actDetectBits &= ~(1 << i);
261     }
262   }
263 }
264 
265 //---------------------------------------------------------
266 //  setMCIn
267 //---------------------------------------------------------
268 
setMCIn(const bool v)269 void MidiSyncInfo::setMCIn(const bool v)
270 {
271   _recMC = v;
272 }
273 
274 //---------------------------------------------------------
275 //  setMRTIn
276 //---------------------------------------------------------
277 
setMRTIn(const bool v)278 void MidiSyncInfo::setMRTIn(const bool v)
279 {
280   _recMRT = v;
281 }
282 
283 //---------------------------------------------------------
284 //  setMMCIn
285 //---------------------------------------------------------
286 
setMMCIn(const bool v)287 void MidiSyncInfo::setMMCIn(const bool v)
288 {
289   _recMMC = v;
290 }
291 
292 //---------------------------------------------------------
293 //  setMTCIn
294 //---------------------------------------------------------
295 
setMTCIn(const bool v)296 void MidiSyncInfo::setMTCIn(const bool v)
297 {
298   _recMTC = v;
299 }
300 
301 //---------------------------------------------------------
302 //  trigMCSyncDetect
303 //---------------------------------------------------------
304 
trigMCSyncDetect()305 void MidiSyncInfo::trigMCSyncDetect()
306 {
307   _clockDetect = true;
308   _clockTrig = true;
309 }
310 
311 //---------------------------------------------------------
312 //  trigTickDetect
313 //---------------------------------------------------------
314 
trigTickDetect()315 void MidiSyncInfo::trigTickDetect()
316 {
317   _tickDetect = true;
318   _tickTrig = true;
319 }
320 
321 //---------------------------------------------------------
322 //  trigMRTDetect
323 //---------------------------------------------------------
324 
trigMRTDetect()325 void MidiSyncInfo::trigMRTDetect()
326 {
327   _MRTDetect = true;
328   _MRTTrig = true;
329 }
330 
331 //---------------------------------------------------------
332 //  trigMMCDetect
333 //---------------------------------------------------------
334 
trigMMCDetect()335 void MidiSyncInfo::trigMMCDetect()
336 {
337   _MMCDetect = true;
338   _MMCTrig = true;
339 }
340 
341 //---------------------------------------------------------
342 //  trigMTCDetect
343 //---------------------------------------------------------
344 
trigMTCDetect()345 void MidiSyncInfo::trigMTCDetect()
346 {
347   _MTCDetect = true;
348   _MTCTrig = true;
349 }
350 
351 //---------------------------------------------------------
352 //  actDetect
353 //---------------------------------------------------------
354 
actDetect(const int ch) const355 bool MidiSyncInfo::actDetect(const int ch) const
356 {
357   if(ch < 0 || ch >= MusECore::MUSE_MIDI_CHANNELS)
358     return false;
359 
360   return _actDetect[ch];
361 }
362 
363 //---------------------------------------------------------
364 //  trigActDetect
365 //---------------------------------------------------------
366 
trigActDetect(const int ch)367 void MidiSyncInfo::trigActDetect(const int ch)
368 {
369   if(ch < 0 || ch >= MusECore::MUSE_MIDI_CHANNELS)
370     return;
371 
372   _actDetectBits |= (1 << ch);
373   _actDetect[ch] = true;
374   _actTrig[ch] = true;
375 }
376 
377 //---------------------------------------------------------
378 //   isDefault
379 //---------------------------------------------------------
380 
isDefault() const381 bool MidiSyncInfo::isDefault() const
382 {
383   return(_idOut == 127 && _idIn == 127 && !_sendMC && !_sendMRT && !_sendMMC && !_sendMTC &&
384      !_recMC && !_recMRT && !_recMMC && !_recMTC && _recRewOnStart);
385 }
386 
387 //---------------------------------------------------------
388 //   read
389 //---------------------------------------------------------
390 
read(Xml & xml)391 void MidiSyncInfo::read(Xml& xml)
392       {
393       for (;;) {
394             Xml::Token token(xml.parse());
395             const QString& tag(xml.s1());
396             switch (token) {
397                   case Xml::Error:
398                   case Xml::End:
399                         return;
400                   case Xml::TagStart:
401                              if (tag == "idOut")
402                               _idOut = xml.parseInt();
403                         else if (tag == "idIn")
404                               _idIn = xml.parseInt();
405                         else if (tag == "sendMC")
406                               _sendMC = xml.parseInt();
407                         else if (tag == "sendMRT")
408                               _sendMRT = xml.parseInt();
409                         else if (tag == "sendMMC")
410                               _sendMMC = xml.parseInt();
411                         else if (tag == "sendMTC")
412                               _sendMTC = xml.parseInt();
413                         else if (tag == "recMC")
414                               _recMC = xml.parseInt();
415                         else if (tag == "recMRT")
416                               _recMRT = xml.parseInt();
417                         else if (tag == "recMMC")
418                               _recMMC = xml.parseInt();
419                         else if (tag == "recMTC")
420                               _recMTC = xml.parseInt();
421                         else if (tag == "recRewStart")
422                               _recRewOnStart = xml.parseInt();
423                         else
424                               xml.unknown("midiSyncInfo");
425                         break;
426                   case Xml::TagEnd:
427                         if (tag == "midiSyncInfo")
428                             return;
429                   default:
430                         break;
431                   }
432             }
433       }
434 
435 //---------------------------------------------------------
436 //  write
437 //---------------------------------------------------------
438 
write(int level,Xml & xml)439 void MidiSyncInfo::write(int level, Xml& xml)
440 {
441   if(isDefault())
442     return;
443 
444   xml.tag(level++, "midiSyncInfo");
445 
446   if(_idOut != 127)
447     xml.intTag(level, "idOut", _idOut);
448   if(_idIn != 127)
449     xml.intTag(level, "idIn", _idIn);
450 
451   if(_sendMC)
452     xml.intTag(level, "sendMC", true);
453   if(_sendMRT)
454     xml.intTag(level, "sendMRT", true);
455   if(_sendMMC)
456     xml.intTag(level, "sendMMC", true);
457   if(_sendMTC)
458     xml.intTag(level, "sendMTC", true);
459 
460   if(_recMC)
461     xml.intTag(level, "recMC", true);
462   if(_recMRT)
463     xml.intTag(level, "recMRT", true);
464   if(_recMMC)
465     xml.intTag(level, "recMMC", true);
466   if(_recMTC)
467     xml.intTag(level, "recMTC", true);
468   if(!_recRewOnStart)
469     xml.intTag(level, "recRewStart", false);
470 
471   xml.etag(level, "midiSyncInfo");
472 }
473 
474 
475 //---------------------------------------------------------
476 //   MidiSyncContainer
477 //---------------------------------------------------------
478 
MidiSyncContainer()479 MidiSyncContainer::MidiSyncContainer()
480 {
481 // REMOVE Tim. clock. Removed.
482   _midiClock = 0;
483   mclock1 = 0.0;
484   mclock2 = 0.0;
485   songtick1 = songtick2 = 0;
486   lastTempo = 0;
487   storedtimediffs = 0;
488   playStateExt = ExtMidiClock::ExternStopped;
489   recTick = 0;
490   recTick1 = 0;
491   recTick2 = 0;
492 
493   _clockAveragerStages = new int[16]; // Max stages is 16!
494 
495   _syncRecFilterPreset = MidiSyncInfo::SMALL;
496   setSyncRecFilterPresetArrays();
497 
498   for(int i = 0; i < _clockAveragerPoles; ++i)
499   {
500     _avgClkDiffCounter[i] = 0;
501     _averagerFull[i] = false;
502   }
503   _tempoQuantizeAmount = 1.0;
504   _lastRealTempo      = 0.0;
505 }
506 
~MidiSyncContainer()507 MidiSyncContainer::~MidiSyncContainer()
508 {
509     if(_clockAveragerStages)
510       delete[] _clockAveragerStages;
511 }
512 
513 //---------------------------------------------------------
514 //  mmcInput
515 //    Midi Machine Control Input received
516 //---------------------------------------------------------
517 
mmcInput(int port,const unsigned char * p,int n)518 void MidiSyncContainer::mmcInput(int port, const unsigned char* p, int n)
519       {
520       if (MusEGlobal::debugSync)
521             fprintf(stderr, "mmcInput: n:%d %02x %02x %02x %02x\n",
522                n, p[2], p[3], p[4], p[5]);
523 
524       MidiPort* mp = &MusEGlobal::midiPorts[port];
525       MidiSyncInfo& msync = mp->syncInfo();
526       // Trigger MMC detect in.
527       msync.trigMMCDetect();
528       // MMC locate SMPTE time code may contain format type bits. Grab them.
529       if(p[3] == 0x44 && p[4] == 6 && p[5] == 1)
530         msync.setRecMTCtype((p[6] >> 5) & 3);
531 
532       // MMC in not turned on? Forget it.
533       if(!msync.MMCIn())
534         return;
535 
536       switch(p[3]) {
537             case 1:
538                   if (MusEGlobal::debugSync)
539                         fprintf(stderr, "  MMC: STOP\n");
540 
541                   playStateExt = ExtMidiClock::ExternStopped;
542 
543                   if (MusEGlobal::audio->isPlaying()) {
544                         MusEGlobal::audio->msgPlay(false);
545                   }
546 
547                   alignAllTicks();
548 
549                   break;
550             case 2:
551                   if (MusEGlobal::debugSync)
552                         fprintf(stderr, "  MMC: PLAY\n");
553             // NOTE: Error suppressor for new gcc 7 'fallthrough' level 3 and 4:
554             // FALLTHROUGH
555             case 3:
556                   if (MusEGlobal::debugSync)
557                         fprintf(stderr, "  MMC: DEFERRED PLAY\n");
558                   MusEGlobal::mtcState = 0;
559                   MusEGlobal::mtcValid = false;
560                   MusEGlobal::mtcLost  = 0;
561                   MusEGlobal::mtcSync  = false;
562                   alignAllTicks();
563                   playStateExt = ExtMidiClock::ExternStarting;
564                   if(MusEGlobal::audio->isRunning() && !MusEGlobal::audio->isPlaying() && MusEGlobal::checkAudioDevice())
565                     MusEGlobal::audioDevice->startTransport();
566 
567                   break;
568 
569             case 4:
570                   fprintf(stderr, "MMC: FF not implemented\n");
571                   break;
572             case 5:
573                   fprintf(stderr, "MMC: REWIND not implemented\n");
574                   break;
575             case 6:
576                   fprintf(stderr, "MMC: REC STROBE not implemented\n");
577                   break;
578             case 7:
579                   fprintf(stderr, "MMC: REC EXIT not implemented\n");
580                   break;
581             case 0xd:
582                   fprintf(stderr, "MMC: RESET not implemented\n");
583                   break;
584             case 0x44:
585                   if (p[5] == 0) {
586                         fprintf(stderr, "MMC: LOCATE IF not implemented\n");
587                         break;
588                         }
589                   else if (p[5] == 1) {
590                         if (!MusEGlobal::checkAudioDevice()) return;
591                         MTC mtc(p[6] & 0x1f, p[7], p[8], p[9], p[10]);
592                         int type = (p[6] >> 5) & 3;
593                         // MTC time resolution is less than frame resolution.
594                         // Round up so that the reciprocal function (frame to time) matches value for value.
595                         unsigned mmcPos = muse_multiply_64_div_64_to_64(mtc.timeUS(type), MusEGlobal::sampleRate, 1000000UL, LargeIntRoundUp);
596 
597                         Pos tp(mmcPos, false);
598                         MusEGlobal::audioDevice->seekTransport(tp);
599                         alignAllTicks();
600                         if (MusEGlobal::debugSync) {
601                               fprintf(stderr, "MMC: LOCATE mtc type:%d timeUS:%lu frame:%u mtc: ", type, (long unsigned)mtc.timeUS(), mmcPos);
602                               mtc.print();
603                               fprintf(stderr, "\n");
604                               }
605                         break;
606                         }
607                   // fall through
608             default:
609                   fprintf(stderr, "MMC %x %x, unknown\n", p[3], p[4]); break;
610             }
611       }
612 
613 //---------------------------------------------------------
614 //   mtcInputQuarter
615 //    process Quarter Frame Message
616 //---------------------------------------------------------
617 
mtcInputQuarter(int port,unsigned char c)618 void MidiSyncContainer::mtcInputQuarter(int port, unsigned char c)
619       {
620       static int hour, min, sec, frame;
621 
622       int valL = c & 0xf;
623       int valH = valL << 4;
624 
625       int _state = (c & 0x70) >> 4;
626       if (MusEGlobal::mtcState != _state)
627             MusEGlobal::mtcLost += _state - MusEGlobal::mtcState;
628       MusEGlobal::mtcState = _state + 1;
629 
630       switch(_state) {
631             case 7:
632                   hour  = (hour  & 0x0f) | valH;
633                   break;
634             case 6:
635                   hour  = (hour  & 0xf0) | valL;
636                   break;
637             case 5:
638                   min   = (min   & 0x0f) | valH;
639                   break;
640             case 4:
641                   min   = (min   & 0xf0) | valL;
642                   break;
643             case 3:
644                   sec   = (sec   & 0x0f) | valH;
645                   break;
646             case 2:
647                   sec   = (sec   & 0xf0) | valL;
648                   break;
649             case 1:
650                   frame = (frame & 0x0f) | valH;
651                   break;
652             case 0:  frame = (frame & 0xf0) | valL;
653                   break;
654             }
655       frame &= 0x1f;    // 0-29
656       sec   &= 0x3f;    // 0-59
657       min   &= 0x3f;    // 0-59
658       int tmphour = hour;
659       int type = (hour >> 5) & 3;
660       hour  &= 0x1f;
661 
662       if(MusEGlobal::mtcState == 8)
663       {
664             MusEGlobal::mtcValid = (MusEGlobal::mtcLost == 0);
665             MusEGlobal::mtcState = 0;
666             MusEGlobal::mtcLost  = 0;
667             if(MusEGlobal::mtcValid)
668             {
669                   MusEGlobal::mtcCurTime.set(hour, min, sec, frame);
670                   if(port != -1)
671                   {
672                     MidiPort* mp = &MusEGlobal::midiPorts[port];
673                     MidiSyncInfo& msync = mp->syncInfo();
674                     msync.setRecMTCtype(type);
675                     msync.trigMTCDetect();
676                     // Not for the current in port? External sync not turned on? MTC in not turned on? Forget it.
677                     if(port == MusEGlobal::config.curMidiSyncInPort && MusEGlobal::extSyncFlag && msync.MTCIn())
678                     {
679                       if(MusEGlobal::debugSync)
680                         fprintf(stderr, "MidiSyncContainer::mtcInputQuarter hour byte:%x\n", (unsigned int)tmphour);
681                       mtcSyncMsg(MusEGlobal::mtcCurTime, type, !MusEGlobal::mtcSync);
682                     }
683                   }
684                   MusEGlobal::mtcSync = true;
685             }
686       }
687       else if (MusEGlobal::mtcValid && (MusEGlobal::mtcLost == 0))
688       {
689             MusEGlobal::mtcCurTime.incQuarter(type);
690       }
691     }
692 
693 //---------------------------------------------------------
694 //   mtcInputFull
695 //    process Frame Message
696 //---------------------------------------------------------
697 
mtcInputFull(int port,const unsigned char * p,int n)698 void MidiSyncContainer::mtcInputFull(int port, const unsigned char* p, int n)
699       {
700       if (MusEGlobal::debugSync)
701             fprintf(stderr, "mtcInputFull\n");
702 
703       if (p[3] != 1) {
704             if (p[3] != 2) {   // silently ignore user bits
705                   fprintf(stderr, "unknown mtc msg subtype 0x%02x\n", p[3]);
706                   dump(p, n);
707                   }
708             return;
709             }
710       int hour  = p[4];
711       int min   = p[5];
712       int sec   = p[6];
713       int frame = p[7];
714 
715       frame &= 0x1f;    // 0-29
716       sec   &= 0x3f;    // 0-59
717       min   &= 0x3f;    // 0-59
718       int type = (hour >> 5) & 3;
719       hour &= 0x1f;
720 
721       MusEGlobal::mtcCurTime.set(hour, min, sec, frame);
722       MusEGlobal::mtcState = 0;
723       MusEGlobal::mtcValid = true;
724       MusEGlobal::mtcLost  = 0;
725 
726       // Added by Tim.
727       if(MusEGlobal::debugSync)
728         fprintf(stderr, "mtcInputFull: timeUS:%lu stimeUS:%lu hour byte (all bits):%hhx\n",
729                 (long unsigned)MusEGlobal::mtcCurTime.timeUS(), (long unsigned)MusEGlobal::mtcCurTime.timeUS(type), p[4]);
730       if(port != -1)
731       {
732         MidiPort* mp = &MusEGlobal::midiPorts[port];
733         MidiSyncInfo& msync = mp->syncInfo();
734         msync.setRecMTCtype(type);
735         msync.trigMTCDetect();
736         // MTC in not turned on? Forget it.
737         if(msync.MTCIn())
738         {
739           // MTC time resolution is less than frame resolution.
740           // Round up so that the reciprocal function (frame to time) matches value for value.
741           const unsigned t_frame = muse_multiply_64_div_64_to_64(MusEGlobal::mtcCurTime.timeUS(type), MusEGlobal::sampleRate, 1000000UL, LargeIntRoundUp);
742 
743           Pos tp(t_frame, false);
744           MusEGlobal::audioDevice->seekTransport(tp);
745           alignAllTicks();
746         }
747       }
748     }
749 
750 //---------------------------------------------------------
751 //   nonRealtimeSystemSysex
752 //---------------------------------------------------------
753 
nonRealtimeSystemSysex(int,const unsigned char * p,int n)754 void MidiSyncContainer::nonRealtimeSystemSysex(int /*port*/, const unsigned char* p, int n)
755       {
756       switch(p[3]) {
757             case 4:
758                   fprintf(stderr, "NRT Setup\n");
759                   break;
760             default:
761                   fprintf(stderr, "unknown NRT Msg 0x%02x\n", p[3]);
762                   dump(p, n);
763                   break;
764            }
765       }
766 
767 //---------------------------------------------------------
768 //   setSongPosition
769 //    MidiBeat is a 14 Bit value. Each MidiBeat spans
770 //    6 MIDI Clocks. Inother words, each MIDI Beat is a
771 //    16th note (since there are 24 MIDI Clocks in a
772 //    quarter note).
773 //---------------------------------------------------------
774 
setSongPosition(int port,int midiBeat)775 void MidiSyncContainer::setSongPosition(int port, int midiBeat)
776       {
777       if (MusEGlobal::midiInputTrace)
778             fprintf(stderr, "set song position port:%d %d\n", port, midiBeat);
779 
780       MusEGlobal::midiPorts[port].syncInfo().trigMRTDetect();
781 
782       if(!MusEGlobal::extSyncFlag || !MusEGlobal::midiPorts[port].syncInfo().MRTIn())
783             return;
784 
785       // Re-transmit song position to other devices if clock out turned on.
786       for(int p = 0; p < MusECore::MIDI_PORTS; ++p)
787         if(p != port && MusEGlobal::midiPorts[p].syncInfo().MRTOut())
788           MusEGlobal::midiPorts[p].sendSongpos(midiBeat);
789 
790       MusEGlobal::curExtMidiSyncTick = (MusEGlobal::config.division * midiBeat) / 4;
791       MusEGlobal::lastExtMidiSyncTick = MusEGlobal::curExtMidiSyncTick;
792 
793       Pos pos(MusEGlobal::curExtMidiSyncTick, true);
794 
795       if (!MusEGlobal::checkAudioDevice()) return;
796 
797       MusEGlobal::audioDevice->seekTransport(pos);
798       alignAllTicks(pos.frame());
799       if (MusEGlobal::debugSync)
800             fprintf(stderr, "setSongPosition %d\n", pos.tick());
801       }
802 
803 
804 
805 //---------------------------------------------------------
806 //   set all runtime variables to the "in sync" value
807 //---------------------------------------------------------
alignAllTicks(int frameOverride)808 void MidiSyncContainer::alignAllTicks(int frameOverride)
809       {
810       unsigned curFrame;
811       if (!frameOverride && MusEGlobal::audio)
812         curFrame = MusEGlobal::audio->pos().frame();
813       else
814         curFrame = frameOverride;
815 
816       int tempo = MusEGlobal::tempomap.tempo(0);
817 
818       // use the last old values to give start values for the tripple buffering
819       int recTickSpan = recTick1 - recTick2;
820       int songTickSpan = (int)(songtick1 - songtick2);    //prevent compiler warning:  casting double to int
821       storedtimediffs = 0; // pretend there is no sync history
822 
823       mclock2=mclock1=0.0; // set all clock values to "in sync"
824 
825       recTick = (int) ((double(curFrame)/double(MusEGlobal::sampleRate)) *
826                         double(MusEGlobal::config.division * 1000000.0) / double(tempo) //prevent compiler warning:  casting double to int
827                 );
828       songtick1 = recTick - songTickSpan;
829       if (songtick1 < 0)
830         songtick1 = 0;
831       songtick2 = songtick1 - songTickSpan;
832       if (songtick2 < 0)
833         songtick2 = 0;
834       recTick1 = recTick - recTickSpan;
835       if (recTick1 < 0)
836         recTick1 = 0;
837       recTick2 = recTick1 - recTickSpan;
838       if (recTick2 < 0)
839         recTick2 = 0;
840       if (MusEGlobal::debugSync)
841         fprintf(stderr, "alignAllTicks curFrame=%d recTick=%d tempo=%.3f frameOverride=%d\n",curFrame,recTick,(float)((1000000.0 * 60.0)/tempo), frameOverride);
842 
843       lastTempo = 0;
844       for(int i = 0; i < _clockAveragerPoles; ++i)
845       {
846         _avgClkDiffCounter[i] = 0;
847         _averagerFull[i] = false;
848       }
849       _lastRealTempo = 0.0;
850       }
851 
852 //---------------------------------------------------------
853 //   realtimeSystemInput
854 //    real time message received
855 //---------------------------------------------------------
realtimeSystemInput(int port,int c)856 void MidiSyncContainer::realtimeSystemInput(int port, int c)
857       {
858 
859       if (MusEGlobal::midiInputTrace)
860             fprintf(stderr, "realtimeSystemInput port:%d 0x%x\n", port+1, c);
861 
862       MidiPort* mp = &MusEGlobal::midiPorts[port];
863 
864       // Trigger on any tick, clock, or realtime command.
865       if(c == ME_TICK) // Tick
866         mp->syncInfo().trigTickDetect();
867       else
868         mp->syncInfo().trigMRTDetect(); // Other
869 
870       // External sync not on? Clock in not turned on? Otherwise realtime in not turned on?
871       if(!MusEGlobal::extSyncFlag)
872         return;
873       if(!mp->syncInfo().MRTIn())
874         return;
875 
876 
877       switch(c) {
878             case ME_TICK:  // midi tick  (every 10 msec)
879                   //DELETETHIS 6
880                   // FIXME: Unfinished? mcStartTick is uninitialized and Song::setPos doesn't set it either. Dangerous to allow this.
881                   //if (mcStart) {
882                   //      song->setPos(0, mcStartTick);
883                   //      mcStart = false;
884                   //      return;
885                   //      }
886                   break;
887             case ME_START:  // start
888                   // Re-transmit start to other devices if clock out turned on.
889                   for(int p = 0; p < MusECore::MIDI_PORTS; ++p)
890                     if(p != port && MusEGlobal::midiPorts[p].syncInfo().MRTOut())
891                     {
892                       // If we aren't rewinding on start, there's no point in re-sending start.
893                       // Re-send continue instead, for consistency.
894                       if(MusEGlobal::midiPorts[port].syncInfo().recRewOnStart())
895                         MusEGlobal::midiPorts[p].sendStart();
896                       else
897                         MusEGlobal::midiPorts[p].sendContinue();
898                     }
899                   if (MusEGlobal::debugSync)
900                         fprintf(stderr, "   start\n");
901 
902 
903                   // DELETETHIS, remove the wrapping if(true)
904                   if (1 /* !MusEGlobal::audio->isPlaying()*/ /*state == IDLE*/) {
905                         if (!MusEGlobal::checkAudioDevice()) return;
906 
907                         playStateExt = ExtMidiClock::ExternStarting;
908 
909                         // Rew on start option.
910                         if(MusEGlobal::midiPorts[port].syncInfo().recRewOnStart())
911                         {
912                           MusEGlobal::curExtMidiSyncTick = 0;
913                           MusEGlobal::lastExtMidiSyncTick = MusEGlobal::curExtMidiSyncTick;
914                           MusEGlobal::audioDevice->seekTransport(Pos(0, false));
915                         }
916 
917                         alignAllTicks();
918                         storedtimediffs = 0;
919                         MusEGlobal::midiExtSyncTicks = 0;
920                         }
921                   break;
922             case ME_CONTINUE:  // continue
923                   // Re-transmit continue to other devices if clock out turned on.
924                   for(int p = 0; p < MusECore::MIDI_PORTS; ++p)
925                     if(p != port && MusEGlobal::midiPorts[p].syncInfo().MRTOut())
926                       MusEGlobal::midiPorts[p].sendContinue();
927 
928                   if (MusEGlobal::debugSync)
929                         fprintf(stderr, "realtimeSystemInput continue\n");
930 
931                   //printf("continue:%f\n", curTime());
932 
933                   if (1 /* !MusEGlobal::audio->isPlaying() */ /*state == IDLE */) {
934                         // Begin incrementing immediately upon first clock reception.
935                         playStateExt = ExtMidiClock::ExternContinuing;
936                         }
937                   break;
938             case ME_STOP:  // stop
939                   {
940                     // Stop the increment right away.
941                     MusEGlobal::midiExtSyncTicks = 0;
942                     playStateExt = ExtMidiClock::ExternStopped;
943 
944                     // Re-transmit stop to other devices if clock out turned on.
945                     for(int p = 0; p < MusECore::MIDI_PORTS; ++p)
946                       if(p != port && MusEGlobal::midiPorts[p].syncInfo().MRTOut())
947                         MusEGlobal::midiPorts[p].sendStop();
948 
949 
950                     if (MusEGlobal::audio->isPlaying())
951                           MusEGlobal::audio->msgPlay(false);
952 
953                     if (MusEGlobal::debugSync)
954                           fprintf(stderr, "realtimeSystemInput stop\n");
955 
956                     //DELETETHIS 7
957                     // Just in case the process still runs a cycle or two and causes the
958                     //  audio tick position to increment, reset the incrementer and force
959                     //  the transport position to what the hardware thinks is the current position.
960                     //MusEGlobal::midiExtSyncTicks = 0;
961                     //Pos pos((MusEGlobal::config.division * lastStoppedBeat) / 4, true);
962                     //Pos pos(MusEGlobal::curExtMidiSyncTick, true);
963                     //MusEGlobal::audioDevice->seekTransport(pos);
964                   }
965 
966                   break;
967             //case 0xfd:  // unknown DELETETHIS 3
968             //case ME_SENSE:  // active sensing
969             //case ME_META:  // system reset (reset is 0xff same enumeration as file meta event)
970             default:
971                   break;
972             }
973 
974       }
975 
976 //---------------------------------------------------------
977 //   midiClockInput
978 //    Midi clock (24 ticks / quarter note)
979 //    Starts transport if necessary. Adds clock to tempo list.
980 //    Returns whether the clock was a 'first clock' after a start or continue message.
981 //---------------------------------------------------------
982 
midiClockInput(int port,unsigned int frame)983 ExtMidiClock MidiSyncContainer::midiClockInput(int port, unsigned int frame)
984 {
985   if(port < 0 || port >= MusECore::MIDI_PORTS)
986     return ExtMidiClock();
987 
988   MidiPort* mp = &MusEGlobal::midiPorts[port];
989 
990   mp->syncInfo().trigMCSyncDetect();
991 
992   // External sync not on? Clock in not turned on? Otherwise realtime in not turned on?
993   if(!MusEGlobal::extSyncFlag)
994     return ExtMidiClock();
995   if(!mp->syncInfo().MCIn())
996     return ExtMidiClock();
997 
998   // Not for the current in port? Forget it.
999   if(port != MusEGlobal::config.curMidiSyncInPort)
1000     return ExtMidiClock();
1001 
1002   //fprintf(stderr, "MidiSyncContainer::midiClockInput: CLOCK port:%d time:%u\n", port, frame);
1003 
1004   // Re-transmit clock to other devices if clock out turned on.
1005   // Must be careful not to allow more than one clock input at a time.
1006   // Would re-transmit mixture of multiple clocks - confusing receivers.
1007   // Solution: Added MusEGlobal::curMidiSyncInPort.
1008   // Maybe in MidiSyncContainer::processTimerTick(), call sendClock for the other devices, instead of here.
1009   for(int p = 0; p < MusECore::MIDI_PORTS; ++p)
1010     if(p != port && MusEGlobal::midiPorts[p].syncInfo().MCOut())
1011       MusEGlobal::midiPorts[p].sendClock();
1012 
1013   MusEGlobal::lastExtMidiSyncFrame = MusEGlobal::curExtMidiSyncFrame;
1014   MusEGlobal::curExtMidiSyncFrame = frame;
1015 
1016   if(MusEGlobal::lastExtMidiSyncFrame > MusEGlobal::curExtMidiSyncFrame)
1017   {
1018     fprintf(stderr,
1019       "MusE: Warning: MidiSyncContainer::midiClockInput(): lastExtMidiSyncFrame:%u > curExtMidiSyncFrame:%u Setting last to cur...\n",
1020       MusEGlobal::lastExtMidiSyncFrame, MusEGlobal::curExtMidiSyncFrame);
1021     MusEGlobal::lastExtMidiSyncFrame = MusEGlobal::curExtMidiSyncFrame;
1022   }
1023 
1024   const int div = MusEGlobal::config.division/24;
1025 
1026   //-------------------------------
1027   // State changes:
1028   //-------------------------------
1029   bool first_clock = false;
1030   if(playStateExt == ExtMidiClock::ExternStarting || playStateExt == ExtMidiClock::ExternContinuing)
1031   {
1032     first_clock = true;
1033     if(playStateExt == ExtMidiClock::ExternStarting)
1034       playStateExt = ExtMidiClock::ExternStarted;
1035     if(playStateExt == ExtMidiClock::ExternContinuing)
1036       playStateExt = ExtMidiClock::ExternContinued;
1037     if(MusEGlobal::audio->isRunning() && !MusEGlobal::audio->isPlaying() && MusEGlobal::checkAudioDevice())
1038       MusEGlobal::audioDevice->startTransport();
1039   }
1040 
1041   //else DELETETHIS?
1042   // This part will be run on the second and subsequent clocks, after start.
1043   // Can't check audio state, might not be playing yet, we might miss some increments.
1044   if(isRunning())
1045   {
1046     MusEGlobal::midiExtSyncTicks += div;
1047     MusEGlobal::lastExtMidiSyncTick = MusEGlobal::curExtMidiSyncTick;
1048     MusEGlobal::curExtMidiSyncTick += div;
1049 
1050     if(MusEGlobal::song->record() && MusEGlobal::curExtMidiSyncFrame > MusEGlobal::lastExtMidiSyncFrame)
1051     {
1052       double diff = double(MusEGlobal::curExtMidiSyncFrame - MusEGlobal::lastExtMidiSyncFrame) / double(MusEGlobal::sampleRate);
1053       if(diff != 0.0)
1054       {
1055 
1056         if(_clockAveragerPoles == 0)
1057         {
1058           double real_tempo = 60.0/(diff * 24.0);
1059           if(_tempoQuantizeAmount > 0.0)
1060           {
1061             double f_mod = fmod(real_tempo, _tempoQuantizeAmount);
1062             if(f_mod < _tempoQuantizeAmount/2.0)
1063               real_tempo -= f_mod;
1064             else
1065               real_tempo += _tempoQuantizeAmount - f_mod;
1066           }
1067           int new_tempo = ((1000000.0 * 60.0) / (real_tempo));
1068           if(new_tempo != lastTempo)
1069           {
1070             lastTempo = new_tempo;
1071             // Compute tick for this tempo - it is one step back in time.
1072             int add_tick = MusEGlobal::curExtMidiSyncTick - div;
1073             if(MusEGlobal::debugSync)
1074               fprintf(stderr, "adding new tempo tick:%d curExtMidiSyncTick:%d avg_diff:%f real_tempo:%f new_tempo:%d = %f\n",
1075                       add_tick, MusEGlobal::curExtMidiSyncTick, diff, real_tempo, new_tempo, (double)((1000000.0 * 60.0)/new_tempo));
1076             MusEGlobal::song->addExternalTempo(TempoRecEvent(add_tick, new_tempo));
1077           }
1078         }
1079         else
1080         {
1081           double avg_diff = diff;
1082           for(int pole = 0; pole < _clockAveragerPoles; ++pole)
1083           {
1084             timediff[pole][_avgClkDiffCounter[pole]] = avg_diff;
1085             ++_avgClkDiffCounter[pole];
1086             if(_avgClkDiffCounter[pole] >= _clockAveragerStages[pole])
1087             {
1088               _avgClkDiffCounter[pole] = 0;
1089               _averagerFull[pole] = true;
1090             }
1091 
1092             // Each averager needs to be full before we can pass the data to
1093             //  the next averager or use the data if all averagers are full...
1094             if(!_averagerFull[pole])
1095               break;
1096             else
1097             {
1098               avg_diff = 0.0;
1099               for(int i = 0; i < _clockAveragerStages[pole]; ++i)
1100                 avg_diff += timediff[pole][i];
1101               avg_diff /= _clockAveragerStages[pole];
1102 
1103               int fin_idx = _clockAveragerPoles - 1;
1104 
1105               // On the first pole? Check for large differences.
1106               if(_preDetect && pole == 0)
1107               {
1108                 double real_tempo = 60.0/(avg_diff * 24.0);
1109                 double real_tempo_diff = fabs(real_tempo - _lastRealTempo);
1110 
1111                 // If the tempo changed a large amount, reset.
1112                 if(real_tempo_diff >= 10.0)  // TODO: User-adjustable?
1113                 {
1114                   if(_tempoQuantizeAmount > 0.0)
1115                   {
1116                     double f_mod = fmod(real_tempo, _tempoQuantizeAmount);
1117                     if(f_mod < _tempoQuantizeAmount/2.0)
1118                       real_tempo -= f_mod;
1119                     else
1120                       real_tempo += _tempoQuantizeAmount - f_mod;
1121                   }
1122                   _lastRealTempo = real_tempo;
1123                   int new_tempo = ((1000000.0 * 60.0) / (real_tempo));
1124 
1125                   if(new_tempo != lastTempo)
1126                   {
1127                     lastTempo = new_tempo;
1128                     // Compute tick for this tempo - it is way back in time.
1129                     int add_tick = MusEGlobal::curExtMidiSyncTick - _clockAveragerStages[0] * div;
1130                     if(add_tick < 0)
1131                     {
1132                       fprintf(stderr, "FIXME sync: adding restart tempo curExtMidiSyncTick:%d: add_tick:%d < 0 !\n",
1133                               MusEGlobal::curExtMidiSyncTick, add_tick);
1134                       add_tick = 0;
1135                     }
1136                     if(MusEGlobal::debugSync)
1137                       fprintf(stderr,
1138                        "adding restart tempo tick:%d curExtMidiSyncTick:%d tick_idx_sub:%d avg_diff:%f real_tempo:%f real_tempo_diff:%f new_tempo:%d = %f\n",
1139                        add_tick, MusEGlobal::curExtMidiSyncTick, _clockAveragerStages[0], avg_diff,
1140                        real_tempo, real_tempo_diff, new_tempo, (double)((1000000.0 * 60.0)/new_tempo));
1141                     MusEGlobal::song->addExternalTempo(TempoRecEvent(add_tick, new_tempo));
1142                   }
1143 
1144                   // Reset all the poles.
1145                   //for(int i = 0; i < clockAveragerPoles; ++i)
1146                   // We have a value for this pole, let's keep it but reset the other poles.
1147                   for(int i = 1; i < _clockAveragerPoles; ++i)
1148                   {
1149                     _avgClkDiffCounter[i] = 0;
1150                     _averagerFull[i] = false;
1151                   }
1152                   break;
1153                 }
1154               }
1155 
1156               // On the last pole?
1157               // All averagers need to be full before we can use the data...
1158               if(pole == fin_idx)
1159               {
1160                 double real_tempo = 60.0/(avg_diff * 24.0);
1161                 double real_tempo_diff = fabs(real_tempo - _lastRealTempo);
1162 
1163                 if(real_tempo_diff >= _tempoQuantizeAmount/2.0) // Anti-hysteresis
1164                 {
1165                   if(_tempoQuantizeAmount > 0.0)
1166                   {
1167                     double f_mod = fmod(real_tempo, _tempoQuantizeAmount);
1168                     if(f_mod < _tempoQuantizeAmount/2.0)
1169                       real_tempo -= f_mod;
1170                     else
1171                       real_tempo += _tempoQuantizeAmount - f_mod;
1172                   }
1173                   _lastRealTempo = real_tempo;
1174                   int new_tempo = ((1000000.0 * 60.0) / (real_tempo));
1175 
1176                   if(new_tempo != lastTempo)
1177                   {
1178                     lastTempo = new_tempo;
1179                     // Compute tick for this tempo - it is way back in time.
1180                     int tick_idx_sub = 0;
1181                     for(int i = 0; i <= pole; ++i)
1182                       tick_idx_sub += _clockAveragerStages[i];
1183                     // Compensate: Each pole > 0 has a delay one less than its number of stages.
1184                     // For example three pole {8, 8, 8} has a delay of 22 not 24.
1185                     tick_idx_sub -= pole;
1186                     int add_tick = MusEGlobal::curExtMidiSyncTick - tick_idx_sub * div;
1187                     if(add_tick < 0)
1188                     {
1189                       fprintf(stderr, "FIXME sync: adding new tempo curExtMidiSyncTick:%d: add_tick:%d < 0 !\n",
1190                              MusEGlobal::curExtMidiSyncTick, add_tick);
1191                       add_tick = 0;
1192                     }
1193                     if(MusEGlobal::debugSync)
1194                       fprintf(stderr, "adding new tempo tick:%d curExtMidiSyncTick:%d tick_idx_sub:%d avg_diff:%f real_tempo:%f new_tempo:%d = %f\n",
1195                               add_tick, MusEGlobal::curExtMidiSyncTick, tick_idx_sub, avg_diff,
1196                               real_tempo, new_tempo, (double)((1000000.0 * 60.0)/new_tempo));
1197                     MusEGlobal::song->addExternalTempo(TempoRecEvent(add_tick, new_tempo));
1198                   }
1199                 }
1200               }
1201             }
1202           }
1203         }
1204       }
1205     }
1206   }
1207   return ExtMidiClock(frame, playStateExt, first_clock);
1208 }
1209 
1210 //---------------------------------------------------------
1211 //   MusEGlobal::mtcSyncMsg
1212 //    process received mtc Sync
1213 //    seekFlag - first complete mtc frame received after
1214 //                start
1215 //---------------------------------------------------------
1216 
mtcSyncMsg(const MTC & mtc,int type,bool seekFlag)1217 void MidiSyncContainer::mtcSyncMsg(const MTC& mtc, int type, bool seekFlag)
1218       {
1219       const uint64_t time = mtc.timeUS();
1220       const uint64_t stime = mtc.timeUS(type);
1221       if (MusEGlobal::debugSync)
1222             fprintf(stderr, "MidiSyncContainer::mtcSyncMsg timeUS:%lu stimeUS:%lu seekFlag:%d\n",
1223                     (long unsigned)time, (long unsigned)stime, seekFlag);
1224 
1225       if (seekFlag && MusEGlobal::audio->isRunning() && !MusEGlobal::audio->isPlaying() && MusEGlobal::checkAudioDevice())
1226       {
1227         if (MusEGlobal::debugSync)
1228           fprintf(stderr, "MidiSyncContainer::mtcSyncMsg starting transport.\n");
1229         MusEGlobal::audioDevice->startTransport();
1230         return;
1231       }
1232 
1233       /*if (tempoSN != MusEGlobal::tempomap.tempoSN()) { DELETETHIS 13
1234             double cpos    = MusEGlobal::tempomap.tick2time(_midiTick, 0);
1235             samplePosStart = samplePos - lrint(cpos * MusEGlobal::sampleRate);
1236             rtcTickStart   = rtcTick - lrint(cpos * realRtcTicks);
1237             tempoSN        = MusEGlobal::tempomap.tempoSN();
1238             }*/
1239 
1240       //
1241       // diff is the time in sec MusE is out of sync
1242       //
1243       /*double diff = time - (double(samplePosStart)/double(MusEGlobal::sampleRate));
1244       if (MusEGlobal::debugSync)
1245             printf("   state %d diff %f\n", MusEGlobal::mtcState, diff);
1246       */
1247       }
1248 
1249 //---------------------------------------------------------
1250 //   setSyncRecFilterPresetArrays
1251 //   To be called in realtime thread only.
1252 //---------------------------------------------------------
setSyncRecFilterPresetArrays()1253 void MidiSyncContainer::setSyncRecFilterPresetArrays()
1254 {
1255   switch(_syncRecFilterPreset)
1256   {
1257     // NOTE: Max _clockAveragerPoles is 16 and maximum stages is 48 per pole !
1258     case MidiSyncInfo::NONE:
1259       _clockAveragerPoles = 0;
1260       _preDetect = false;
1261     break;
1262     case MidiSyncInfo::TINY:
1263       _clockAveragerPoles = 2;
1264       _clockAveragerStages[0] = 4;
1265       _clockAveragerStages[1] = 4;
1266       _preDetect = false;
1267     break;
1268     case MidiSyncInfo::SMALL:
1269       _clockAveragerPoles = 3;
1270       _clockAveragerStages[0] = 12;
1271       _clockAveragerStages[1] = 8;
1272       _clockAveragerStages[2] = 4;
1273       _preDetect = false;
1274     break;
1275     case MidiSyncInfo::MEDIUM:
1276       _clockAveragerPoles = 3;
1277       _clockAveragerStages[0] = 28;
1278       _clockAveragerStages[1] = 12;
1279       _clockAveragerStages[2] = 8;
1280       _preDetect = false;
1281     break;
1282     case MidiSyncInfo::LARGE:
1283       _clockAveragerPoles = 4;
1284       _clockAveragerStages[0] = 48;
1285       _clockAveragerStages[1] = 48;
1286       _clockAveragerStages[2] = 48;
1287       _clockAveragerStages[3] = 48;
1288       _preDetect = false;
1289     break;
1290     case MidiSyncInfo::LARGE_WITH_PRE_DETECT:
1291       _clockAveragerPoles = 4;
1292       _clockAveragerStages[0] = 8;
1293       _clockAveragerStages[1] = 48;
1294       _clockAveragerStages[2] = 48;
1295       _clockAveragerStages[3] = 48;
1296       _preDetect = true;
1297     break;
1298 
1299     default:
1300       fprintf(stderr, "MidiSyncContainer::setSyncRecFilterPresetArrays unknown preset type:%d\n", (int)_syncRecFilterPreset);
1301   }
1302 }
1303 
1304 //---------------------------------------------------------
1305 //   setSyncRecFilterPreset
1306 //   To be called in realtime thread only.
1307 //---------------------------------------------------------
setSyncRecFilterPreset(MidiSyncInfo::SyncRecFilterPresetType type)1308 void MidiSyncContainer::setSyncRecFilterPreset(MidiSyncInfo::SyncRecFilterPresetType type)
1309 {
1310   _syncRecFilterPreset = type;
1311   setSyncRecFilterPresetArrays();
1312   alignAllTicks();
1313 }
1314 
1315 
1316 } // namespace MusECore
1317