1 //=========================================================
2 //  MusE
3 //  Linux Music Editor
4 //  $Id: mididev.cpp,v 1.10.2.6 2009/11/05 03:14:35 terminator356 Exp $
5 //
6 //  (C) Copyright 1999-2004 Werner Schweer (ws@seh.de)
7 //  (C) Copyright 2011, 2016 Tim E. Real (terminator356 on users dot sourceforge dot 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 <config.h>
26 
27 #include <QMessageBox>
28 #include <stdio.h>
29 #include <unistd.h>
30 #include <errno.h>
31 
32 #include "midictrl.h"
33 #include "song.h"
34 #include "midi_consts.h"
35 #include "midiport.h"
36 #include "mididev.h"
37 #include "config.h"
38 #include "gconfig.h"
39 #include "globals.h"
40 #include "audio.h"
41 #include "audiodev.h"
42 #include "midiseq.h"
43 #include "midiitransform.h"
44 #include "mitplugin.h"
45 #include "part.h"
46 #include "drummap.h"
47 #include "helper.h"
48 #include "ticksynth.h"
49 
50 // Forwards from header:
51 #include "xml.h"
52 
53 // Undefine if and when multiple output routes are added to midi tracks.
54 #define _USE_MIDI_TRACK_SINGLE_OUT_PORT_CHAN_
55 
56 // For debugging output: Uncomment the fprintf section.
57 //#define DEBUG_MIDI_DEVICE(dev, format, args...)  //fprintf(dev, format, ##args);
58 
59 namespace MusEGlobal {
60 MusECore::MidiDeviceList midiDevices;
61 }
62 
63 namespace MusECore {
64 
65 #ifdef MIDI_DRIVER_MIDI_SERIAL
66 extern void initMidiSerial();
67 #endif
68 extern bool initMidiAlsa();
69 extern bool initMidiJack();
70 
71 extern void processMidiInputTransformPlugins(MEvent&);
72 
73 // Static.
74 const int MidiDevice::extClockHistoryCapacity = 1024;
75 
76 
77 //---------------------------------------------------------
78 //   initMidiDevices
79 //---------------------------------------------------------
80 
initMidiDevices()81 void initMidiDevices()
82       {
83 #ifdef MIDI_DRIVER_MIDI_SERIAL
84       initMidiSerial();
85 #endif
86 #ifdef ALSA_SUPPORT
87       if(MusEGlobal::config.enableAlsaMidiDriver ||                         // User setting
88          MusEGlobal::useAlsaWithJack ||                                     // Command line override
89          MusEGlobal::audioDevice->deviceType() != AudioDevice::JACK_AUDIO)  // Jack not running
90       {
91         if(initMidiAlsa())
92           {
93           QMessageBox::critical(NULL, "MusE fatal error.", "MusE failed to initialize the\n"
94                                                           "Alsa midi subsystem, check\n"
95                                                           "your configuration.");
96           exit(-1);
97           }
98       }
99 #endif
100 
101       if(initMidiJack())
102           {
103           QMessageBox::critical(NULL, "MusE fatal error.", "MusE failed to initialize the\n"
104                                                           "Jack midi subsystem, check\n"
105                                                           "your configuration.");
106           exit(-1);
107           }
108       }
109 
110 //---------------------------------------------------------
111 //   init
112 //---------------------------------------------------------
113 
init()114 void MidiDevice::init()
115       {
116       _extClockHistoryFifo = new LockFreeBuffer<ExtMidiClock>(extClockHistoryCapacity);
117 
118       // TODO: Scale these according to the current audio segment size.
119       _playbackEventBuffers = new LockFreeMPSCRingBuffer<MidiPlayEvent>(1024);
120       _userEventBuffers = new LockFreeMPSCRingBuffer<MidiPlayEvent>(1024);
121 
122       _sysExOutDelayedEvents = new std::vector<MidiPlayEvent>;
123       // Initially reserve a fair number of items to hold potentially a lot
124       //  of messages when the sysex processor is busy (in the Sending state).
125       _sysExOutDelayedEvents->reserve(1024);
126       _stopFlag.store(false);
127 
128       _state         = QString("Closed");
129       _readEnable    = false;
130       _writeEnable   = false;
131       _rwFlags       = 3;
132       _openFlags     = 3;
133       _port          = -1;
134       }
135 
136 //---------------------------------------------------------
137 //   MidiDevice
138 //---------------------------------------------------------
139 
MidiDevice()140 MidiDevice::MidiDevice()
141       {
142       for(unsigned int i = 0; i < MusECore::MUSE_MIDI_CHANNELS + 1; ++i)
143         _tmpRecordCount[i] = 0;
144 
145       _sysexFIFOProcessed = false;
146 
147       init();
148       }
149 
MidiDevice(const QString & n)150 MidiDevice::MidiDevice(const QString& n)
151    : _name(n)
152       {
153       for(unsigned int i = 0; i < MusECore::MUSE_MIDI_CHANNELS + 1; ++i)
154         _tmpRecordCount[i] = 0;
155 
156       _sysexFIFOProcessed = false;
157 
158       init();
159       }
160 
~MidiDevice()161 MidiDevice::~MidiDevice()
162 {
163     if(_sysExOutDelayedEvents)
164       delete _sysExOutDelayedEvents;
165     if(_extClockHistoryFifo)
166       delete _extClockHistoryFifo;
167     if(_userEventBuffers)
168       delete _userEventBuffers;
169     if(_playbackEventBuffers)
170       delete _playbackEventBuffers;
171 }
172 
deviceTypeString() const173 QString MidiDevice::deviceTypeString() const
174 {
175   switch(deviceType())
176   {
177     case ALSA_MIDI:
178         return "ALSA";
179     case JACK_MIDI:
180         return "JACK";
181     case SYNTH_MIDI:
182     {
183       const SynthI* s = dynamic_cast<const SynthI*>(this);
184       if(s && s->synth())
185         return MusECore::synthType2String(s->synth()->synthType());
186       else
187         return "SYNTH";
188     }
189   }
190   return "UNKNOWN";
191 }
192 
setPort(int p)193 void MidiDevice::setPort(int p)
194 {
195   _port = p;
196   if(_port != -1)
197     MusEGlobal::midiPorts[_port].clearInitSent();
198 }
199 
200 //---------------------------------------------------------
201 //   filterEvent
202 //    return true if event filtered
203 //---------------------------------------------------------
204 
filterEvent(const MEvent & event,int type,bool thru)205 bool filterEvent(const MEvent& event, int type, bool thru)
206       {
207       switch(event.type()) {
208             case ME_NOTEON:
209             case ME_NOTEOFF:
210                   if (type & MIDI_FILTER_NOTEON)
211                         return true;
212                   break;
213             case ME_POLYAFTER:
214                   if (type & MIDI_FILTER_POLYP)
215                         return true;
216                   break;
217             case ME_CONTROLLER:
218                   if (type & MIDI_FILTER_CTRL)
219                         return true;
220                   if (!thru && (MusEGlobal::midiFilterCtrl1 == event.dataA()
221                      || MusEGlobal::midiFilterCtrl2 == event.dataA()
222                      || MusEGlobal::midiFilterCtrl3 == event.dataA()
223                      || MusEGlobal::midiFilterCtrl4 == event.dataA())) {
224                         return true;
225                         }
226                   break;
227             case ME_PROGRAM:
228                   if (type & MIDI_FILTER_PROGRAM)
229                         return true;
230                   break;
231             case ME_AFTERTOUCH:
232                   if (type & MIDI_FILTER_AT)
233                         return true;
234                   break;
235             case ME_PITCHBEND:
236                   if (type & MIDI_FILTER_PITCH)
237                         return true;
238                   break;
239             case ME_SYSEX:
240                   if (type & MIDI_FILTER_SYSEX)
241                         return true;
242                   break;
243             default:
244                   break;
245             }
246       return false;
247       }
248 
249 //---------------------------------------------------------
250 //   afterProcess
251 //    clear all recorded events after a process cycle
252 //---------------------------------------------------------
253 
afterProcess()254 void MidiDevice::afterProcess()
255 {
256   for(unsigned int i = 0; i < MusECore::MUSE_MIDI_CHANNELS + 1; ++i)
257   {
258     while (_tmpRecordCount[i]--)
259       _recordFifo[i].remove();
260   }
261 }
262 
263 //---------------------------------------------------------
264 //   beforeProcess
265 //    "freeze" fifo for this process cycle
266 //---------------------------------------------------------
267 
beforeProcess()268 void MidiDevice::beforeProcess()
269 {
270   for(unsigned int i = 0; i < MusECore::MUSE_MIDI_CHANNELS + 1; ++i)
271     _tmpRecordCount[i] = _recordFifo[i].getSize();
272 
273   // Reset this.
274   _sysexFIFOProcessed = false;
275 }
276 
277 //---------------------------------------------------------
278 //   midiClockInput
279 //    Midi clock (24 ticks / quarter note)
280 //---------------------------------------------------------
281 
midiClockInput(unsigned int frame)282 void MidiDevice::midiClockInput(unsigned int frame)
283 {
284   // Put a midi clock record event into the clock history fifo. Ignore port and channel.
285   // Timestamp with the current frame.
286   const ExtMidiClock ext_clk = MusEGlobal::midiSyncContainer.midiClockInput(midiPort(), frame);
287   if(ext_clk.isValid() && extClockHistory())
288     extClockHistory()->put(ext_clk);
289 }
290 
291 //---------------------------------------------------------
292 //   recordEvent
293 //---------------------------------------------------------
294 
recordEvent(MidiRecordEvent & event)295 void MidiDevice::recordEvent(MidiRecordEvent& event)
296       {
297       if(MusEGlobal::audio->isPlaying())
298         event.setLoopNum(MusEGlobal::audio->loopCount());
299 
300       if (MusEGlobal::midiInputTrace) {
301             fprintf(stderr, "MidiInput: ");
302             dumpMPEvent(&event);
303             }
304 
305       int typ = event.type();
306 
307       if(_port != -1)
308       {
309         int idin = MusEGlobal::midiPorts[_port].syncInfo().idIn();
310 
311         //---------------------------------------------------
312         // filter some SYSEX events
313         //---------------------------------------------------
314 
315         if (typ == ME_SYSEX) {
316               const unsigned char* p = event.data();
317               int n = event.len();
318               if (n >= 4) {
319                     if ((p[0] == 0x7f)
320                       && ((p[1] == 0x7f) || (idin == 0x7f) || (p[1] == idin))) {
321                           if (p[2] == 0x06) {
322                                 MusEGlobal::midiSyncContainer.mmcInput(_port, p, n);
323                                 return;
324                                 }
325                           if (p[2] == 0x01) {
326                                 MusEGlobal::midiSyncContainer.mtcInputFull(_port, p, n);
327                                 return;
328                                 }
329                           }
330                     else if (p[0] == 0x7e) {
331                           MusEGlobal::midiSyncContainer.nonRealtimeSystemSysex(_port, p, n);
332                           return;
333                           }
334                     }
335           }
336           else
337             // Trigger general activity indicator detector. Sysex has no channel, don't trigger.
338             MusEGlobal::midiPorts[_port].syncInfo().trigActDetect(event.channel());
339       }
340 
341       //
342       //  process midi event input filtering and
343       //    transformation
344       //
345 
346       processMidiInputTransformPlugins(event);
347 
348       if (filterEvent(event, MusEGlobal::midiRecordType, false))
349             return;
350 
351       if (!applyMidiInputTransformation(event)) {
352             if (MusEGlobal::midiInputTrace)
353                   fprintf(stderr, "   midi input transformation: event filtered\n");
354             return;
355             }
356 
357       //
358       // transfer noteOn and Off events to gui for step recording and keyboard
359       // remote control (changed by flo93: added noteOff-events)
360       //
361       if (typ == ME_NOTEON) {
362             int pv = ((event.dataA() & 0xff)<<8) + (event.dataB() & 0xff);
363             MusEGlobal::song->putEvent(pv);
364             }
365       else if (typ == ME_NOTEOFF) {
366             int pv = ((event.dataA() & 0xff)<<8) + (0x00); //send an event with velo=0
367             MusEGlobal::song->putEvent(pv);
368             }
369       else if (MusEGlobal::rcEnableCC && typ == ME_CONTROLLER) {
370           char cc = static_cast<char>(event.dataA() & 0xff);
371           printf("*** Input CC: %d\n", cc);
372           MusEGlobal::song->putEventCC(cc);
373       }
374 
375       // Do not bother recording if it is NOT actually being used by a port.
376       // Because from this point on, process handles things, by selected port.
377       if(_port == -1)
378         return;
379 
380       // Split the events up into channel fifos. Special 'channel' number 17 for sysex events.
381       unsigned int ch = (typ == ME_SYSEX)? MusECore::MUSE_MIDI_CHANNELS : event.channel();
382       if(_recordFifo[ch].put(event))
383         fprintf(stderr, "MidiDevice::recordEvent: fifo channel %d overflow\n", ch);
384       }
385 
386 //---------------------------------------------------------
387 //   find
388 //---------------------------------------------------------
389 
find(const QString & s,int typeHint)390 MidiDevice* MidiDeviceList::find(const QString& s, int typeHint)
391       {
392       for (iMidiDevice i = begin(); i != end(); ++i)
393             if( (typeHint == -1 || typeHint == (*i)->deviceType()) && ((*i)->name() == s) )
394                   return *i;
395       return 0;
396       }
397 
398 //---------------------------------------------------------
399 //   add
400 //---------------------------------------------------------
401 
add(MidiDevice * dev)402 void MidiDeviceList::add(MidiDevice* dev)
403       {
404       bool gotUniqueName=false;
405       int increment = 0;
406       const QString origname = dev->name();
407       QString newName = origname;
408       while (!gotUniqueName) {
409             gotUniqueName = true;
410             // check if the name's been taken
411             for (iMidiDevice i = begin(); i != end(); ++i) {
412                   const QString s = (*i)->name();
413                   if (s == newName)
414                         {
415                         newName = origname + QString("_%1").arg(++increment);
416                         gotUniqueName = false;
417                         }
418                   }
419             }
420       if(origname != newName)
421         dev->setName(newName);
422       push_back(dev);
423       }
424 
425 //---------------------------------------------------------
426 //   remove
427 //---------------------------------------------------------
428 
remove(MidiDevice * dev)429 void MidiDeviceList::remove(MidiDevice* dev)
430       {
431       for (iMidiDevice i = begin(); i != end(); ++i) {
432             if (*i == dev) {
433                   erase(i);
434                   break;
435                   }
436             }
437       }
438 
439 //---------------------------------------------------------
440 //   resetCurParamNums
441 //   Reset output channel's current parameter numbers to -1.
442 //   All channels if chan = -1.
443 //---------------------------------------------------------
444 
resetCurOutParamNums(int chan)445 void MidiDevice::resetCurOutParamNums(int chan)
446 {
447   if(chan == -1)
448   {
449     for(int i = 0; i < MusECore::MUSE_MIDI_CHANNELS; ++i)
450       _curOutParamNums[i].resetParamNums();
451     return;
452   }
453   _curOutParamNums[chan].resetParamNums();
454 }
455 
456 //---------------------------------------------------------
457 //   putEvent
458 //    return true if event cannot be delivered
459 //---------------------------------------------------------
460 
putEvent(const MidiPlayEvent & ev,LatencyType latencyType,EventBufferType bufferType)461 bool MidiDevice::putEvent(const MidiPlayEvent& ev, LatencyType latencyType, EventBufferType bufferType)
462 {
463 // TODO: Decide whether we want the driver cached values always updated like this,
464 //        even if not writeable or if error.
465 //   if(!_writeEnable)
466 //     return true;
467 
468   // Automatically shift the time forward if specified.
469   MidiPlayEvent fin_ev = ev;
470   switch(latencyType)
471   {
472     case NotLate:
473     break;
474 
475     case Late:
476       fin_ev.setTime(fin_ev.time() + pbForwardShiftFrames());
477     break;
478   }
479 
480   //DEBUG_MIDI_DEVICE(stderr, "MidiDevice::putUserEvent devType:%d time:%d type:%d ch:%d A:%d B:%d\n",
481   //                  deviceType(), fin_ev.time(), fin_ev.type(), fin_ev.channel(), fin_ev.dataA(), fin_ev.dataB());
482   if (MusEGlobal::midiOutputTrace)
483   {
484     fprintf(stderr, "MidiDevice::putEvent: %s: <%s>: ", deviceTypeString().toLatin1().constData(), name().toLatin1().constData());
485     dumpMPEvent(&fin_ev);
486   }
487 
488   bool rv = true;
489   switch(bufferType)
490   {
491     case PlaybackBuffer:
492       rv = !_playbackEventBuffers->put(fin_ev);
493     break;
494 
495     case UserBuffer:
496       rv = !_userEventBuffers->put(fin_ev);
497     break;
498   }
499 
500   if(rv)
501     fprintf(stderr, "MidiDevice::putEvent: Error: Device buffer overflow. bufferType:%d\n", bufferType);
502 
503   return rv;
504 }
505 
506 //---------------------------------------------------------
507 //   processStuckNotes
508 //   To be called by audio thread only.
509 //---------------------------------------------------------
510 
processStuckNotes()511 void MidiDevice::processStuckNotes()
512 {
513   // Must be playing for valid nextTickPos, right? But wasn't checked in Audio::processMidi().
514   // MusEGlobal::audio->isPlaying() might not be true during seek right now.
515   //if(MusEGlobal::audio->isPlaying())
516   {
517     const bool extsync = MusEGlobal::extSyncFlag;
518     const unsigned syncFrame = MusEGlobal::audio->curSyncFrame();
519     const unsigned curTickPos = MusEGlobal::audio->tickPos();
520     const unsigned nextTick = MusEGlobal::audio->nextTick();
521     // What is the current transport frame?
522     const unsigned int pos_fr = MusEGlobal::audio->pos().frame();
523     // What is the (theoretical) next transport frame?
524     const unsigned int next_pos_fr = pos_fr + MusEGlobal::audio->curCycleFrames();
525     ciMPEvent k;
526 
527     //---------------------------------------------------
528     //    Play any stuck notes which were put directly to the device
529     //---------------------------------------------------
530 
531     for (k = _stuckNotes.begin(); k != _stuckNotes.end(); ++k) {
532           MidiPlayEvent ev(*k);
533           unsigned int off_tick = ev.time();
534           // If external sync is not on, we can take advantage of frame accuracy but
535           //  first we must allow the next tick position to be included in the search
536           //  even if it is equal to the current tick position.
537           if (extsync ? (off_tick >= nextTick) : (off_tick > nextTick))
538                 break;
539           unsigned int off_frame = 0;
540           if(extsync)
541           {
542             if(off_tick < curTickPos)
543               off_tick = curTickPos;
544             off_frame = MusEGlobal::audio->extClockHistoryTick2Frame(off_tick - curTickPos) + MusEGlobal::segmentSize;
545           }
546           else
547           {
548             // What is the exact transport frame that the event should be played at?
549             const unsigned int fr = MusEGlobal::tempomap.tick2frame(off_tick);
550             // Is the event frame outside of the current transport frame range?
551             if(fr >= next_pos_fr)
552               break;
553             off_frame = (fr < pos_fr) ? 0 : fr - pos_fr;
554             off_frame += syncFrame;
555           }
556           ev.setTime(off_frame);
557 
558           _userEventBuffers->put(ev);
559           }
560     _stuckNotes.erase(_stuckNotes.begin(), k);
561 
562     //------------------------------------------------------------
563     //    To save time, playing of any track-related playback stuck notes (NOT 'live' notes)
564     //     which were not put directly to the device, is done in Audio::processMidi().
565     //------------------------------------------------------------
566   }
567 }
568 
569 //---------------------------------------------------------
570 //   handleStop
571 //   To be called by audio thread only.
572 //---------------------------------------------------------
573 
handleStop()574 void MidiDevice::handleStop()
575 {
576   // If the device is not in use by a port, don't bother it.
577   if(_port == -1)
578     return;
579 
580   MidiPort* mp = &MusEGlobal::midiPorts[_port];
581 
582   //---------------------------------------------------
583   //    send midi stop
584   //---------------------------------------------------
585 
586   // Don't send if external sync is on. The master, and our sync routing system will take care of that.
587   if(!MusEGlobal::extSyncFlag)
588   {
589     // Shall we check open flags? DELETETHIS 4?
590     //if(!(dev->rwFlags() & 0x1) || !(dev->openFlags() & 1))
591     //if(!(dev->openFlags() & 1))
592     //  return;
593 
594     MidiSyncInfo& si = mp->syncInfo();
595     if(si.MMCOut())
596       mp->sendMMCStop();
597 
598     if(si.MRTOut())
599     {
600       mp->sendStop();
601       //DELETETHIS 5?
602       // Added check of option send continue not start. Hmm, is this required? Seems to make other devices unhappy.
603       // (Could try now that this is in MidiDevice.)
604       //if(!si.sendContNotStart())
605       //  mp->sendSongpos(MusEGlobal::audio->tickPos() * 4 / MusEGlobal::config.division);
606     }
607   }
608 
609   //---------------------------------------------------
610   //    Clear all notes and flush out any stuck notes
611   //     which were put directly to the device
612   //---------------------------------------------------
613 
614   setStopFlag(true);
615   for(iMPEvent i = _stuckNotes.begin(); i != _stuckNotes.end(); ++i)
616   {
617     MidiPlayEvent ev(*i);
618     ev.setTime(0);  // Immediate processing. TODO Use curFrame?
619     //ev.setTime(MusEGlobal::audio->midiQueueTimeStamp(ev.time()));
620         putEvent(ev, MidiDevice::NotLate);
621   }
622   _stuckNotes.clear();
623 
624   //------------------------------------------------------------
625   //    Flush out any track-related playback stuck notes (NOT 'live' notes)
626   //     which were not put directly to the device
627   //------------------------------------------------------------
628 
629   for(ciMidiTrack imt = MusEGlobal::song->midis()->begin(); imt != MusEGlobal::song->midis()->end(); ++imt)
630   {
631     MPEventList& mel = (*imt)->stuckNotes;
632     for(iMPEvent i = mel.begin(), i_next = i; i != mel.end(); i = i_next)
633     {
634       ++i_next;
635 
636       if((*i).port() != _port)
637         continue;
638       MidiPlayEvent ev(*i);
639       ev.setTime(0);  // Immediate processing. TODO Use curFrame?
640       //ev.setTime(MusEGlobal::audio->midiQueueTimeStamp(ev.time()));
641       putEvent(ev, MidiDevice::NotLate);
642 
643       mel.erase(i);
644     }
645   }
646 
647   //---------------------------------------------------
648   //    reset sustain
649   //---------------------------------------------------
650 
651   for(int ch = 0; ch < MusECore::MUSE_MIDI_CHANNELS; ++ch)
652   {
653     if(mp->hwCtrlState(ch, CTRL_SUSTAIN) == 127)
654     {
655       MidiPlayEvent ev(0, _port, ch, ME_CONTROLLER, CTRL_SUSTAIN, 0); // Immediate processing. TODO Use curFrame?
656       //ev.setTime(MusEGlobal::audio->midiQueueTimeStamp(ev.time()));
657       putEvent(ev, MidiDevice::NotLate);
658     }
659   }
660 }
661 
662 //---------------------------------------------------------
663 //   handleSeek
664 //   To be called by audio thread only.
665 //---------------------------------------------------------
666 
handleSeek()667 void MidiDevice::handleSeek()
668 {
669   //---------------------------------------------------
670   //    If playing, clear all notes and flush out any
671   //     stuck notes which were put directly to the device
672   //---------------------------------------------------
673 
674   if(MusEGlobal::audio->isPlaying())
675   {
676     // TODO: Don't clear, let it play whatever was scheduled ?
677     //setStopFlag(true);
678     for(iMPEvent i = _stuckNotes.begin(); i != _stuckNotes.end(); ++i)
679     {
680       MidiPlayEvent ev(*i);
681       ev.setTime(0); // Immediate processing. TODO Use curFrame?
682       //ev.setTime(MusEGlobal::audio->midiQueueTimeStamp(ev.time()));
683       putEvent(ev, MidiDevice::NotLate);
684     }
685     _stuckNotes.clear();
686   }
687 }
688 
689 //================================================
690 // BEGIN Latency correction/compensation routines.
691 //================================================
692 
prepareLatencyScan()693 void MidiDevice::prepareLatencyScan() {
694   // Reset some latency info to prepare for (re)computation.
695   _captureLatencyInfo.initialize();
696   _playbackLatencyInfo.initialize();
697 }
698 
isLatencyInputTerminalMidi(bool capture)699 bool MidiDevice::isLatencyInputTerminalMidi(bool capture)
700 {
701   TrackLatencyInfo* tli = capture ? &_captureLatencyInfo : &_playbackLatencyInfo;
702 
703   // Have we been here before during this scan?
704   // Just return the cached value.
705   if(tli->_isLatencyInputTerminalProcessed)
706     return tli->_isLatencyInputTerminal;
707 
708   const int port = midiPort();
709 
710   // Playback devices are considered a termination point.
711   if(!capture || port < 0 || port >= MusECore::MIDI_PORTS)
712   {
713     tli->_isLatencyInputTerminal = true;
714     tli->_isLatencyInputTerminalProcessed = true;
715     return true;
716   }
717 
718   MidiPort* mp = &MusEGlobal::midiPorts[port];
719   const RouteList* rl = mp->outRoutes();
720   for (ciRoute ir = rl->begin(); ir != rl->end(); ++ir) {
721     switch(ir->type)
722     {
723       case Route::TRACK_ROUTE:
724         if(!ir->track)
725           continue;
726         if(ir->track->isMidiTrack())
727         {
728           Track* track = ir->track;
729           if(track->off()) // ||
730             //(atrack->canRecordMonitor() && (MusEGlobal::config.monitoringAffectsLatency || !atrack->isRecMonitored())))
731               //&& atrack->canRecord() && !atrack->recordFlag()))
732             continue;
733 
734           tli->_isLatencyInputTerminal = false;
735           tli->_isLatencyInputTerminalProcessed = true;
736           return false;
737         }
738       break;
739 
740       default:
741       break;
742     }
743   }
744 
745   tli->_isLatencyInputTerminal = true;
746   tli->_isLatencyInputTerminalProcessed = true;
747   return true;
748 }
749 
isLatencyOutputTerminalMidi(bool capture)750 bool MidiDevice::isLatencyOutputTerminalMidi(bool capture)
751 {
752   TrackLatencyInfo* tli = capture ? &_captureLatencyInfo : &_playbackLatencyInfo;
753 
754   // Have we been here before during this scan?
755   // Just return the cached value.
756   if(tli->_isLatencyOutputTerminalProcessed)
757     return tli->_isLatencyOutputTerminal;
758 
759   const int port = midiPort();
760 
761   // Playback devices are considered a termination point.
762   if(!capture || port < 0 || port >= MusECore::MIDI_PORTS)
763   {
764     tli->_isLatencyOutputTerminal = true;
765     tli->_isLatencyOutputTerminalProcessed = true;
766     return true;
767   }
768 
769   MidiPort* mp = &MusEGlobal::midiPorts[port];
770   const RouteList* rl = mp->outRoutes();
771   for (ciRoute ir = rl->begin(); ir != rl->end(); ++ir) {
772     switch(ir->type)
773     {
774       case Route::TRACK_ROUTE:
775         if(!ir->track)
776           continue;
777         if(ir->track->isMidiTrack())
778         {
779           Track* track = ir->track;
780           if(track->off()) // ||
781             //(atrack->canRecordMonitor() && (MusEGlobal::config.monitoringAffectsLatency || !atrack->isRecMonitored())))
782               //&& atrack->canRecord() && !atrack->recordFlag()))
783             continue;
784 
785           tli->_isLatencyOutputTerminal = false;
786           tli->_isLatencyOutputTerminalProcessed = true;
787           return false;
788         }
789       break;
790 
791       default:
792       break;
793     }
794   }
795 
796   tli->_isLatencyOutputTerminal = true;
797   tli->_isLatencyOutputTerminalProcessed = true;
798   return true;
799 }
800 
801 //---------------------------------------------------------
802 //   getWorstSelfLatencyMidi
803 //---------------------------------------------------------
804 
getWorstSelfLatencyMidi(bool capture)805 float MidiDevice::getWorstSelfLatencyMidi(bool capture)
806 {
807   TrackLatencyInfo* tli = capture ? &_captureLatencyInfo : &_playbackLatencyInfo;
808 
809   // Have we been here before during this scan?
810   // Just return the cached value.
811   if(tli->_worstSelfLatencyMidiProcessed)
812     return tli->_worstSelfLatencyMidi;
813 
814 // REMOVE Tim. latency. Changed. TESTING. Reinstate.
815 //   for(int i = 0; i < MusECore::MUSE_MIDI_CHANNELS; ++i)
816   {
817     //if(!used_chans[i])
818     //  continue;
819 //     const float lat = selfLatencyMidi(i, capture);
820     const float lat = selfLatencyMidi(0, capture);
821     //const float lat = selfLatencyMidi(i, 0 /*playback*/);
822     if(lat > tli->_worstSelfLatencyMidi)
823       tli->_worstSelfLatencyMidi = lat;
824   }
825 
826   // The absolute latency of signals leaving this track is the sum of
827   //  any connected route latencies and this track's latency.
828   tli->_worstSelfLatencyMidiProcessed = true;
829   return tli->_worstSelfLatencyMidi;
830 }
831 
canDominateOutputLatencyMidi(bool capture) const832 inline bool MidiDevice::canDominateOutputLatencyMidi(bool capture) const
833 {
834   if(capture)
835     return true;
836   return false;
837 }
838 
canDominateInputLatencyMidi(bool) const839 inline bool MidiDevice::canDominateInputLatencyMidi(bool /*capture*/) const
840 {
841   return false;
842 }
843 
canDominateEndPointLatencyMidi(bool capture) const844 inline bool MidiDevice::canDominateEndPointLatencyMidi(bool capture) const
845 {
846   if(capture)
847     return false;
848   return true;
849 }
850 
canPassThruLatencyMidi(bool) const851 inline bool MidiDevice::canPassThruLatencyMidi(bool /*capture*/) const
852 {
853   return true;
854 }
855 
856 //---------------------------------------------------------
857 //   getDominanceInfoMidi
858 //---------------------------------------------------------
859 
getDominanceInfoMidi(bool capture,bool input)860 TrackLatencyInfo& MidiDevice::getDominanceInfoMidi(bool capture, bool input)
861 {
862       TrackLatencyInfo* tli = capture ? &_captureLatencyInfo : &_playbackLatencyInfo;
863 
864       // Have we been here before during this scan?
865       // Just return the cached value.
866       if((input && tli->_canDominateInputProcessed) ||
867         (!input && tli->_canDominateProcessed))
868         return *tli;
869 
870       // Get the default domination for this track type.
871       bool can_dominate_lat = input ? canDominateInputLatencyMidi(capture) : canDominateOutputLatencyMidi(capture);
872       bool can_correct_lat = canCorrectOutputLatencyMidi();
873 
874       const bool passthru = canPassThruLatencyMidi(capture);
875 
876       bool item_found = false;
877 
878       const int port = midiPort();
879       const int open_flags = openFlags();
880 
881       // Gather latency info from all connected input branches,
882       //  but ONLY if the track is not off.
883       // Currently there are no routes FROM tracks (audio or midi) TO midi capture devices,
884       //  only TO midi playback devices.
885       // CAUTION: The ABSENCE of the '!capture' caused an infinite loop crash, where
886       //  MidiDevice::getDominanceInfoMidi called Track::getDominanceInfo which called
887       //  MidiDevice::getDominanceInfoMidi again, and repeat inf...
888       // When that happens, all the "Have we been here before...?" checks say 'no'
889       //  because each call has not finished yet, where at the end we say 'yes'.
890       // So I'm not sure how we could support the above future plan, if any.
891       if(!capture && (open_flags & (/*capture ? 2 :*/ 1)) && (passthru || input) &&
892         port >= 0 && port < MusECore::MIDI_PORTS)
893       {
894 //         bool used_chans[MusECore::MUSE_MIDI_CHANNELS];
895 //         for(int i = 0; i < MusECore::MUSE_MIDI_CHANNELS; ++i)
896 //           used_chans[i] = false;
897 //         bool all_chans = false;
898 
899 #ifdef _USE_MIDI_TRACK_SINGLE_OUT_PORT_CHAN_
900         const MidiTrackList& tl = *MusEGlobal::song->midis();
901         const MidiTrackList::size_type tl_sz = tl.size();
902         for(MidiTrackList::size_type it = 0; it < tl_sz; ++it)
903         {
904           MidiTrack* track = static_cast<MidiTrack*>(tl[it]);
905           if(track->outPort() != port)
906             continue;
907 
908           //if((open_flags & (/*capture ? 2 :*/ 1)) && !track->off() && (passthru || input))
909           if(!track->off())
910           {
911             const TrackLatencyInfo& li = track->getDominanceInfo(false);
912 
913             // Whether the branch can dominate or correct latency or if we
914             //  want to allow unterminated input branches to
915             //  participate in worst branch latency calculations.
916             const bool participate =
917               (li._canCorrectOutputLatency ||
918               li._canDominateOutputLatency ||
919               MusEGlobal::config.correctUnterminatedInBranchLatency);
920 
921             if(participate)
922             {
923               // Is it the first found item?
924               if(item_found)
925               {
926                 // If any one of the branches can dominate the latency,
927                 //  that overrides any which cannot.
928                 if(li._canDominateOutputLatency)
929                   can_dominate_lat = true;
930                 if(li._canCorrectOutputLatency)
931                   can_correct_lat = true;
932               }
933               else
934               {
935                 item_found = true;
936                 // Override the defaults with this first item's values.
937                 can_dominate_lat = li._canDominateOutputLatency;
938                 can_correct_lat = li._canCorrectOutputLatency;
939               }
940             }
941           }
942         }
943 
944 #else
945 
946         MidiPort* mp = &MusEGlobal::midiPorts[port];
947         RouteList* rl = mp->inRoutes();
948         for (iRoute ir = rl->begin(); ir != rl->end(); ++ir)
949         {
950           switch(ir->type)
951           {
952               case Route::TRACK_ROUTE:
953                 if(!ir->track)
954                   continue;
955 
956                 if(ir->track->isMidiTrack())
957                 {
958                   if(ir->channel < -1 || ir->channel >= MusECore::MUSE_MIDI_CHANNELS)
959                     continue;
960 
961                   Track* track = ir->track;
962 //                     if(ir->channel < 0)
963 //                       all_chans = true;
964 //                     else
965 //                       used_chans[ir->channel] = true;
966 
967                   //if((open_flags & (/*capture ? 2 :*/ 1)) && !track->off() && (passthru || input))
968                   if(!track->off())
969                   {
970                     const TrackLatencyInfo& li = track->getDominanceInfo(false);
971 
972                     // Whether the branch can dominate or correct latency or if we
973                     //  want to allow unterminated input branches to
974                     //  participate in worst branch latency calculations.
975                     const bool participate =
976                       (li._canCorrectOutputLatency ||
977                       li._canDominateOutputLatency ||
978                       MusEGlobal::config.correctUnterminatedInBranchLatency);
979 
980                     if(participate)
981                     {
982                       // Is it the first found item?
983                       if(item_found)
984                       {
985                         // If any one of the branches can dominate the latency,
986                         //  that overrides any which cannot.
987                         if(li._canDominateOutputLatency)
988                           can_dominate_lat = true;
989                         if(li._canCorrectOutputLatency)
990                           can_correct_lat = true;
991                       }
992                       else
993                       {
994                         item_found = true;
995                         // Override the defaults with this first item's values.
996                         can_dominate_lat = li._canDominateOutputLatency;
997                         can_correct_lat = li._canCorrectOutputLatency;
998                       }
999                     }
1000                   }
1001                 }
1002               break;
1003 
1004               default:
1005               break;
1006           }
1007         }
1008 
1009 #endif
1010 
1011         // Special for the built-in metronome.
1012         //if(!capture)
1013         //{
1014           MusECore::MetronomeSettings* metro_settings =
1015             MusEGlobal::metroUseSongSettings ? &MusEGlobal::metroSongSettings : &MusEGlobal::metroGlobalSettings;
1016 
1017           if(metro_settings->midiClickFlag && metro_settings->clickPort == port)
1018           {
1019             //if((open_flags & (/*capture ? 2 :*/ 1)) && !MusECore::metronome->off() && (passthru || input))
1020             if(!MusECore::metronome->off())
1021             {
1022               const TrackLatencyInfo& li = MusECore::metronome->getDominanceInfoMidi(capture, false);
1023 
1024               // Whether the branch can dominate or correct latency or if we
1025               //  want to allow unterminated input branches to
1026               //  participate in worst branch latency calculations.
1027               const bool participate =
1028                 (li._canCorrectOutputLatency ||
1029                 li._canDominateOutputLatency ||
1030                 MusEGlobal::config.correctUnterminatedInBranchLatency);
1031 
1032               if(participate)
1033               {
1034                 // Is it the first found item?
1035                 if(item_found)
1036                 {
1037                   // If any one of the branches can dominate the latency,
1038                   //  that overrides any which cannot.
1039                   if(li._canDominateOutputLatency)
1040                     can_dominate_lat = true;
1041                   if(li._canCorrectOutputLatency)
1042                     can_correct_lat = true;
1043                 }
1044                 else
1045                 {
1046                   item_found = true;
1047                   // Override the defaults with this first item's values.
1048                   //route_worst_out_corr = li._outputAvailableCorrection;
1049                   can_dominate_lat = li._canDominateOutputLatency;
1050                   can_correct_lat = li._canCorrectOutputLatency;
1051                 }
1052               }
1053             }
1054           }
1055         //}
1056       }
1057 
1058       // Set the correction of all connected input branches,
1059       //  but ONLY if the track is not off.
1060       if((open_flags & (capture ? 2 : 1)))
1061       {
1062         if(input)
1063         {
1064           tli->_canDominateInputLatency = can_dominate_lat;
1065         }
1066         else
1067         {
1068           tli->_canDominateOutputLatency = can_dominate_lat;
1069           // If any of the branches can dominate, then this node cannot correct.
1070           tli->_canCorrectOutputLatency = can_correct_lat && !can_dominate_lat;
1071         }
1072       }
1073 
1074       if(input)
1075         tli->_canDominateInputProcessed = true;
1076       else
1077         tli->_canDominateProcessed = true;
1078 
1079       return *tli;
1080 }
1081 
1082 //---------------------------------------------------------
1083 //   getDominanceLatencyInfoMidi
1084 //---------------------------------------------------------
1085 
getDominanceLatencyInfoMidi(bool capture,bool input)1086 TrackLatencyInfo& MidiDevice::getDominanceLatencyInfoMidi(bool capture, bool input)
1087 {
1088       TrackLatencyInfo* tli = capture ? &_captureLatencyInfo : &_playbackLatencyInfo;
1089 
1090       // Have we been here before during this scan?
1091       // Just return the cached value.
1092       if((input && tli->_dominanceInputProcessed) ||
1093         (!input && tli->_dominanceProcessed))
1094         return *tli;
1095 
1096       float route_worst_latency = 0.0f;
1097 
1098       const bool passthru = canPassThruLatencyMidi(capture);
1099 
1100       bool item_found = false;
1101 
1102       const int open_flags = openFlags();
1103 
1104       float worst_self_latency = 0.0f;
1105       if(!input && (open_flags & (capture ? 2 : 1)))
1106         worst_self_latency = getWorstSelfLatencyMidi(capture);
1107 
1108       const int port = midiPort();
1109 
1110       // Gather latency info from all connected input branches,
1111       //  but ONLY if the track is not off.
1112       // Currently there are no routes FROM tracks (audio or midi) TO midi capture devices,
1113       //  only TO midi playback devices.
1114       // CAUTION: See the warning in getDominanceInfoMidi about infinite recursion.
1115       if(!capture && (open_flags & (/*capture ? 2 :*/ 1)) && (passthru || input) &&
1116         port >= 0 && port < MusECore::MIDI_PORTS)
1117       {
1118 //         bool used_chans[MusECore::MUSE_MIDI_CHANNELS];
1119 //         for(int i = 0; i < MusECore::MUSE_MIDI_CHANNELS; ++i)
1120 //           used_chans[i] = false;
1121 //         bool all_chans = false;
1122 
1123 #ifdef _USE_MIDI_TRACK_SINGLE_OUT_PORT_CHAN_
1124         const MidiTrackList& tl = *MusEGlobal::song->midis();
1125         const MidiTrackList::size_type tl_sz = tl.size();
1126         for(MidiTrackList::size_type it = 0; it < tl_sz; ++it)
1127         {
1128           MidiTrack* track = static_cast<MidiTrack*>(tl[it]);
1129           if(track->outPort() != port)
1130             continue;
1131 
1132           //if((open_flags & (/*capture ? 2 :*/ 1)) && !track->off() && (passthru || input))
1133           if(!track->off())
1134           {
1135             const TrackLatencyInfo& li = track->getDominanceLatencyInfo(false);
1136 
1137             // Whether the branch can dominate or correct latency or if we
1138             //  want to allow unterminated input branches to
1139             //  participate in worst branch latency calculations.
1140             const bool participate =
1141               (li._canCorrectOutputLatency ||
1142               li._canDominateOutputLatency ||
1143               MusEGlobal::config.correctUnterminatedInBranchLatency);
1144 
1145             if(participate)
1146             {
1147               // Is it the first found item?
1148               if(item_found)
1149               {
1150                 // If any one of the branches can dominate the latency,
1151                 //  that overrides any which cannot.
1152                 if(li._canDominateOutputLatency)
1153                 {
1154                   // Override the current worst value if the latency is greater,
1155                   //  but ONLY if the branch can dominate.
1156                   //if(li._outputLatency > route_worst_latency)
1157                   //  route_worst_latency = li._outputLatency;
1158                 }
1159                 // Override the current worst value if the latency is greater,
1160                 //  but ONLY if the branch can dominate.
1161                 if(li._outputLatency > route_worst_latency)
1162                   route_worst_latency = li._outputLatency;
1163               }
1164               else
1165               {
1166                 item_found = true;
1167                 // Override the default worst value, but ONLY if the branch can dominate.
1168                 //if(li._canDominateOutputLatency)
1169                   route_worst_latency = li._outputLatency;
1170               }
1171             }
1172           }
1173         }
1174 
1175 #else
1176 
1177         MidiPort* mp = &MusEGlobal::midiPorts[port];
1178         RouteList* rl = mp->inRoutes();
1179         for (iRoute ir = rl->begin(); ir != rl->end(); ++ir)
1180         {
1181           switch(ir->type)
1182           {
1183               case Route::TRACK_ROUTE:
1184                 if(!ir->track)
1185                   continue;
1186 
1187                 if(ir->track->isMidiTrack())
1188                 {
1189                   if(ir->channel < -1 || ir->channel >= MusECore::MUSE_MIDI_CHANNELS)
1190                     continue;
1191 
1192                   Track* track = ir->track;
1193 //                     if(ir->channel < 0)
1194 //                       all_chans = true;
1195 //                     else
1196 //                       used_chans[ir->channel] = true;
1197 
1198                   //if((open_flags & (/*capture ? 2 :*/ 1)) && !track->off() && (passthru || input))
1199                   if(!track->off())
1200                   {
1201                     const TrackLatencyInfo& li = track->getDominanceLatencyInfo(false);
1202 
1203                     // Whether the branch can dominate or correct latency or if we
1204                     //  want to allow unterminated input branches to
1205                     //  participate in worst branch latency calculations.
1206                     const bool participate =
1207                       (li._canCorrectOutputLatency ||
1208                       li._canDominateOutputLatency ||
1209                       MusEGlobal::config.correctUnterminatedInBranchLatency);
1210 
1211                     if(participate)
1212                     {
1213                       // Is it the first found item?
1214                       if(item_found)
1215                       {
1216                         // If any one of the branches can dominate the latency,
1217                         //  that overrides any which cannot.
1218                         if(li._canDominateOutputLatency)
1219                         {
1220                           // Override the current worst value if the latency is greater,
1221                           //  but ONLY if the branch can dominate.
1222                           //if(li._outputLatency > route_worst_latency)
1223                           //  route_worst_latency = li._outputLatency;
1224                         }
1225                         // Override the current worst value if the latency is greater,
1226                         //  but ONLY if the branch can dominate.
1227                         if(li._outputLatency > route_worst_latency)
1228                           route_worst_latency = li._outputLatency;
1229                       }
1230                       else
1231                       {
1232                         item_found = true;
1233                         // Override the default worst value, but ONLY if the branch can dominate.
1234                         //if(li._canDominateOutputLatency)
1235                           route_worst_latency = li._outputLatency;
1236                       }
1237                     }
1238                   }
1239                 }
1240               break;
1241 
1242               default:
1243               break;
1244           }
1245         }
1246 
1247 #endif
1248 
1249         // Special for the built-in metronome.
1250         //if(!capture)
1251         //{
1252           MusECore::MetronomeSettings* metro_settings =
1253             MusEGlobal::metroUseSongSettings ? &MusEGlobal::metroSongSettings : &MusEGlobal::metroGlobalSettings;
1254 
1255           //if(sendMetronome())
1256           if(metro_settings->midiClickFlag && metro_settings->clickPort == port)
1257           {
1258             //if((open_flags & (/*capture ? 2 :*/ 1)) && !MusECore::metronome->off() && (passthru || input))
1259             if(!MusECore::metronome->off())
1260             {
1261               const TrackLatencyInfo& li = MusECore::metronome->getDominanceLatencyInfoMidi(capture, false);
1262 
1263               // Whether the branch can dominate or correct latency or if we
1264               //  want to allow unterminated input branches to
1265               //  participate in worst branch latency calculations.
1266               const bool participate =
1267                 (li._canCorrectOutputLatency ||
1268                 li._canDominateOutputLatency ||
1269                 MusEGlobal::config.correctUnterminatedInBranchLatency);
1270 
1271               if(participate)
1272               {
1273                 // Is it the first found item?
1274                 if(item_found)
1275                 {
1276                   // If any one of the branches can dominate the latency,
1277                   //  that overrides any which cannot.
1278                   if(li._canDominateOutputLatency)
1279                   {
1280                     // Override the current worst value if the latency is greater,
1281                     //  but ONLY if the branch can dominate.
1282                     //if(li._outputLatency > route_worst_latency)
1283                     //  route_worst_latency = li._outputLatency;
1284                   }
1285                   // Override the current worst value if the latency is greater,
1286                   //  but ONLY if the branch can dominate.
1287                   if(li._outputLatency > route_worst_latency)
1288                     route_worst_latency = li._outputLatency;
1289                 }
1290                 else
1291                 {
1292                   item_found = true;
1293                   // Override the default worst value, but ONLY if the branch can dominate.
1294                   //if(li._canDominateOutputLatency)
1295                     route_worst_latency = li._outputLatency;
1296                 }
1297               }
1298             }
1299           }
1300         //}
1301       }
1302 
1303       // Set the correction of all connected input branches,
1304       //  but ONLY if the track is not off.
1305       if((open_flags & (capture ? 2 : 1)))
1306       {
1307         if(input)
1308         {
1309           tli->_inputLatency = route_worst_latency;
1310         }
1311         else
1312         {
1313           if(passthru)
1314           {
1315             tli->_outputLatency = worst_self_latency + route_worst_latency;
1316             tli->_inputLatency = route_worst_latency;
1317           }
1318           else
1319           {
1320             tli->_outputLatency = worst_self_latency + tli->_sourceCorrectionValue;
1321           }
1322         }
1323       }
1324 
1325       if(input)
1326         tli->_dominanceInputProcessed = true;
1327       else
1328         tli->_dominanceProcessed = true;
1329 
1330       return *tli;
1331 }
1332 
1333 //---------------------------------------------------------
1334 //   setCorrectionLatencyInfoMidi
1335 //---------------------------------------------------------
1336 
setCorrectionLatencyInfoMidi(bool capture,bool input,float finalWorstLatency,float callerBranchLatency)1337 TrackLatencyInfo& MidiDevice::setCorrectionLatencyInfoMidi(bool capture, bool input, float finalWorstLatency, float callerBranchLatency)
1338 {
1339   TrackLatencyInfo* tli = capture ? &_captureLatencyInfo : &_playbackLatencyInfo;
1340 
1341   const bool passthru = canPassThruLatencyMidi(capture);
1342 
1343   const int open_flags = openFlags();
1344 
1345   float worst_self_latency = 0.0f;
1346   if(!input && (open_flags & 1 /*write*/))
1347     worst_self_latency = getWorstSelfLatencyMidi(capture);
1348 
1349   // The _trackLatency should already be calculated in the dominance scan.
1350   const float branch_lat = callerBranchLatency + worst_self_latency;
1351 
1352   const int port = midiPort();
1353   // Currently there are no routes FROM tracks (audio or midi) TO midi capture devices,
1354   //  only TO midi playback devices.
1355   // CAUTION: See the warning in getDominanceInfoMidi about infinite recursion.
1356   if(!capture && (open_flags & 1 /*write*/) && (passthru || input) &&
1357     port >= 0 && port < MusECore::MIDI_PORTS)
1358   {
1359     // Set the correction of all connected input branches.
1360     // The _trackLatency should already be calculated in the dominance scan.
1361 #ifdef _USE_MIDI_TRACK_SINGLE_OUT_PORT_CHAN_
1362     const MidiTrackList& tl = *MusEGlobal::song->midis();
1363     const MidiTrackList::size_type tl_sz = tl.size();
1364     for(MidiTrackList::size_type it = 0; it < tl_sz; ++it)
1365     {
1366       MidiTrack* track = static_cast<MidiTrack*>(tl[it]);
1367       if(track->outPort() != port)
1368         continue;
1369       //if((open_flags & 1 /*write*/) && !track->off() && (passthru || input))
1370       if(!track->off())
1371         track->setCorrectionLatencyInfo(false, finalWorstLatency, branch_lat);
1372     }
1373 
1374 #else
1375 
1376     MidiPort* mp = &MusEGlobal::midiPorts[port];
1377     RouteList* mrl = mp->inRoutes();
1378     for (iRoute ir = mrl->begin(); ir != mrl->end(); ++ir)
1379     {
1380       switch(ir->type)
1381       {
1382           case Route::TRACK_ROUTE:
1383             if(!ir->track)
1384               continue;
1385 
1386             if(ir->track->isMidiTrack())
1387             {
1388               if(ir->channel < -1 || ir->channel >= MusECore::MUSE_MIDI_CHANNELS)
1389                 continue;
1390               Track* track = ir->track;
1391               //if((open_flags & 1 /*write*/) && !track->off() && (passthru || input))
1392               if(!track->off())
1393                 track->setCorrectionLatencyInfo(false, finalWorstLatency, branch_lat);
1394             }
1395           break;
1396 
1397           default:
1398           break;
1399       }
1400     }
1401 
1402 #endif
1403 
1404     // Special for the built-in metronome.
1405     //if(!capture)
1406     //{
1407       MusECore::MetronomeSettings* metro_settings =
1408         MusEGlobal::metroUseSongSettings ? &MusEGlobal::metroSongSettings : &MusEGlobal::metroGlobalSettings;
1409 
1410       //if(sendMetronome())
1411       if(metro_settings->midiClickFlag && metro_settings->clickPort == port)
1412       {
1413         //if((open_flags & 1 /*write*/) && !MusECore::metronome->off() && (passthru || input))
1414         if(!MusECore::metronome->off())
1415           MusECore::metronome->setCorrectionLatencyInfoMidi(capture, false, finalWorstLatency, branch_lat);
1416       }
1417     //}
1418   }
1419 
1420   // Set the correction of all connected input branches,
1421   //  but ONLY if the track is not off.
1422   if(open_flags & 1 /*write*/ && !capture/*Tim*/)
1423   {
1424     if(input)
1425     {
1426     }
1427     else
1428     {
1429       if(canCorrectOutputLatencyMidi() && tli->_canCorrectOutputLatency)
1430       {
1431         float corr = 0.0f;
1432         if(MusEGlobal::config.commonProjectLatency)
1433           corr -= finalWorstLatency;
1434 
1435         corr -= branch_lat;
1436         // The _sourceCorrectionValue is initialized to zero.
1437         // Whichever calling branch needs the most correction gets it.
1438         if(corr < tli->_sourceCorrectionValue)
1439           tli->_sourceCorrectionValue = corr;
1440       }
1441     }
1442   }
1443 
1444   return *tli;
1445 }
1446 
1447 //---------------------------------------------------------
1448 //   getLatencyInfoMidi
1449 //---------------------------------------------------------
1450 
getLatencyInfoMidi(bool capture,bool input)1451 TrackLatencyInfo& MidiDevice::getLatencyInfoMidi(bool capture, bool input)
1452 {
1453   TrackLatencyInfo* tli = capture ? &_captureLatencyInfo : &_playbackLatencyInfo;
1454 
1455   // Have we been here before during this scan?
1456   // Just return the cached value.
1457   if((input && tli->_inputProcessed) ||
1458     (!input && tli->_processed))
1459     return *tli;
1460 
1461   MusECore::MetronomeSettings* metro_settings =
1462     MusEGlobal::metroUseSongSettings ? &MusEGlobal::metroSongSettings : &MusEGlobal::metroGlobalSettings;
1463 
1464   float route_worst_latency = tli->_inputLatency;
1465 
1466   const bool passthru = canPassThruLatencyMidi(capture);
1467 
1468   const int port = midiPort();
1469   const int open_flags = openFlags();
1470 
1471   if(passthru || input)
1472   {
1473     // Currently there are no routes FROM tracks (audio or midi) TO midi capture devices,
1474     //  only TO midi playback devices.
1475     // CAUTION: See the warning in getDominanceInfoMidi about infinite recursion.
1476     if(!capture && port >= 0 && port < MusECore::MIDI_PORTS)
1477     {
1478   #ifdef _USE_MIDI_TRACK_SINGLE_OUT_PORT_CHAN_
1479       const MidiTrackList& tl = *MusEGlobal::song->midis();
1480       const MidiTrackList::size_type tl_sz = tl.size();
1481       for(MidiTrackList::size_type it = 0; it < tl_sz; ++it)
1482       {
1483         MidiTrack* track = static_cast<MidiTrack*>(tl[it]);
1484         if(track->outPort() != port)
1485           continue;
1486 
1487         // TODO: FIXME: Where to store? We have no route to store it in.
1488         // Default to zero.
1489         //ir->audioLatencyOut = 0.0f;
1490 
1491         if((open_flags & (/*capture ? 2 :*/ 1)) && !track->off())
1492         {
1493           TrackLatencyInfo& li = track->getLatencyInfo(false);
1494 
1495           const bool participate =
1496             (li._canCorrectOutputLatency ||
1497             li._canDominateOutputLatency ||
1498             MusEGlobal::config.correctUnterminatedInBranchLatency);
1499 
1500           if(participate)
1501           {
1502             // TODO: FIXME: Where to store? We have no route to store it in.
1503             // Prepare the latency value to be passed to the compensator's writer,
1504             //  by adjusting each route latency value. ie. the route with the worst-case
1505             //  latency will get ZERO delay, while routes having smaller latency will get
1506             //  MORE delay, to match all the signal timings together.
1507             // The route's audioLatencyOut should have already been calculated and
1508             //  conveniently stored in the route.
1509 //             ir->audioLatencyOut = route_worst_latency - li._outputLatency;
1510 //             // Should not happen, but just in case.
1511 //             if((long int)ir->audioLatencyOut < 0)
1512 //               ir->audioLatencyOut = 0.0f;
1513 
1514             // Special for Midi Tracks: We don't have Midi Track to Midi Port routes yet
1515             //  because we don't have multiple Midi Track outputs yet, only a single output port.
1516             // So we must store this information here just for Midi Tracks.
1517             li._latencyOutMidiTrack = route_worst_latency - li._outputLatency;
1518             // Should not happen, but just in case.
1519             if((long int)li._latencyOutMidiTrack < 0)
1520               li._latencyOutMidiTrack = 0.0f;
1521           }
1522         }
1523       }
1524 
1525   #else
1526 
1527       MidiPort* mp = &MusEGlobal::midiPorts[port];
1528       RouteList* rl = mp->inRoutes();
1529       for (iRoute ir = rl->begin(); ir != rl->end(); ++ir)
1530       {
1531             switch(ir->type)
1532             {
1533                 case Route::TRACK_ROUTE:
1534                   if(!ir->track)
1535                     continue;
1536 
1537                   if(ir->track->isMidiTrack())
1538                   {
1539                     if(ir->channel < -1 || ir->channel >= MusECore::MUSE_MIDI_CHANNELS)
1540                       continue;
1541 
1542                     Track* track = ir->track;
1543 
1544                     // Default to zero.
1545                     ir->audioLatencyOut = 0.0f;
1546 
1547                     if((open_flags & (/*capture ? 2 :*/ 1)) && !track->off())
1548                     {
1549                       const TrackLatencyInfo& li = track->getLatencyInfo(false);
1550                       const bool participate =
1551                         (li._canCorrectOutputLatency ||
1552                         li._canDominateOutputLatency ||
1553                         MusEGlobal::config.correctUnterminatedInBranchLatency);
1554 
1555                       if(participate)
1556                       {
1557                         // Prepare the latency value to be passed to the compensator's writer,
1558                         //  by adjusting each route latency value. ie. the route with the worst-case
1559                         //  latency will get ZERO delay, while routes having smaller latency will get
1560                         //  MORE delay, to match all the signal timings together.
1561                         // The route's audioLatencyOut should have already been calculated and
1562                         //  conveniently stored in the route.
1563                         ir->audioLatencyOut = route_worst_latency - li._outputLatency;
1564                         // Should not happen, but just in case.
1565                         if((long int)ir->audioLatencyOut < 0)
1566                           ir->audioLatencyOut = 0.0f;
1567                       }
1568                     }
1569                   }
1570                 break;
1571 
1572                 default:
1573                 break;
1574             }
1575       }
1576 
1577   #endif
1578 
1579       // Special for the built-in metronome.
1580       //if(!capture)
1581       //{
1582         // TODO: FIXME: Where to store? We have no route to store it in.
1583         // Default to zero.
1584         //ir->audioLatencyOut = 0.0f;
1585 
1586         if((open_flags & (/*capture ? 2 :*/ 1)) && !MusECore::metronome->off() && // sendMetronome() &&
1587           metro_settings->midiClickFlag && metro_settings->clickPort == port)
1588         {
1589           TrackLatencyInfo& li = MusECore::metronome->getLatencyInfoMidi(capture, false);
1590           const bool participate =
1591             (li._canCorrectOutputLatency ||
1592             li._canDominateOutputLatency ||
1593             MusEGlobal::config.correctUnterminatedInBranchLatency);
1594 
1595           if(participate)
1596           {
1597             // TODO: FIXME: Where to store? We have no route to store it in.
1598             // Prepare the latency value to be passed to the compensator's writer,
1599             //  by adjusting each route latency value. ie. the route with the worst-case
1600             //  latency will get ZERO delay, while routes having smaller latency will get
1601             //  MORE delay, to match all the signal timings together.
1602             // The route's audioLatencyOut should have already been calculated and
1603             //  conveniently stored in the route.
1604 
1605 //             ir->audioLatencyOut = route_worst_latency - ir->audioLatencyOut;
1606 //             // Should not happen, but just in case.
1607 //             if((long int)ir->audioLatencyOut < 0)
1608 //               ir->audioLatencyOut = 0.0f;
1609 
1610             // Special for Midi Tracks: We don't have Midi Track to Midi Port routes yet
1611             //  because we don't have multiple Midi Track outputs yet, only a single output port.
1612             // So we must store this information here just for Midi Tracks.
1613 //             li._latencyOutMidiTrack = route_worst_latency - li._outputLatency;
1614 //             // Should not happen, but just in case.
1615 //             if((long int)li._latencyOutMidiTrack < 0)
1616 //               li._latencyOutMidiTrack = 0.0f;
1617 
1618             // Special for Midi Tracks: We don't have Midi Track to Midi Port routes yet
1619             //  because we don't have multiple Midi Track outputs yet, only a single output port.
1620             // So we must store this information here just for Midi Tracks.
1621             li._latencyOutMetronome = route_worst_latency - li._latencyOutMetronome;
1622             // Should not happen, but just in case.
1623             if((long int)li._latencyOutMetronome < 0)
1624               li._latencyOutMetronome = 0.0f;
1625           }
1626         }
1627       //}
1628     }
1629   }
1630 
1631   if(input)
1632     tli->_inputProcessed = true;
1633   else
1634     tli->_processed = true;
1635 
1636   return *tli;
1637 }
1638 
1639 //---------------------------------------------------------
1640 //   latencyCompWriteOffset
1641 //---------------------------------------------------------
1642 
latencyCompWriteOffsetMidi(bool capture) const1643 inline unsigned long MidiDevice::latencyCompWriteOffsetMidi(bool capture) const
1644 {
1645   return capture ? _captureLatencyInfo._compensatorWriteOffset : _playbackLatencyInfo._compensatorWriteOffset;
1646 }
1647 
setLatencyCompWriteOffsetMidi(float worstCase,bool capture)1648 void MidiDevice::setLatencyCompWriteOffsetMidi(float worstCase, bool capture)
1649 {
1650   TrackLatencyInfo* tli = capture ? &_captureLatencyInfo : &_playbackLatencyInfo;
1651 
1652   // If independent branches are NOT to affect project latency,
1653   //  then there should be no need for any extra delay in the branch.
1654   if(!MusEGlobal::config.commonProjectLatency)
1655   {
1656     tli->_compensatorWriteOffset = 0;
1657     //fprintf(stderr, "MidiDevice::setLatencyCompWriteOffset() name:%s capture:%d worstCase:%f _outputLatency:%f _compensatorWriteOffset:%lu\n",
1658     //        name().toLatin1().constData(), capture, worstCase, tli->_outputLatency, tli->_compensatorWriteOffset);
1659     return;
1660   }
1661 
1662   if(tli->_canDominateOutputLatency)
1663   {
1664     const long unsigned int wc = worstCase;
1665     const long unsigned int ol = tli->_outputLatency;
1666     if(ol > wc)
1667       tli->_compensatorWriteOffset = 0;
1668     else
1669       tli->_compensatorWriteOffset = wc - ol;
1670   }
1671   else
1672   {
1673 //     if(tli->_outputLatency < 0)
1674       tli->_compensatorWriteOffset = 0;
1675 //     else
1676 //       tli->_compensatorWriteOffset = tli->_outputLatency;
1677   }
1678 
1679   //fprintf(stderr,
1680   //  "MidiDevice::setLatencyCompWriteOffset() name:%s capture:%d worstCase:%f"
1681   //  " _outputLatency:%f _canDominateOutputLatency:%d _compensatorWriteOffset:%lu\n",
1682   //     name().toLatin1().constData(), capture, worstCase, tli->_outputLatency,
1683   //     tli->_canDominateOutputLatency, tli->_compensatorWriteOffset);
1684 }
1685 
1686 //================================================
1687 // END Latency correction/compensation routines.
1688 //================================================
1689 
1690 
1691 } // namespace MusECore
1692 
1693