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