1 //=========================================================
2 // MusE
3 // Linux Music Editor
4 // $Id: track.cpp,v 1.34.2.11 2009/11/30 05:05:49 terminator356 Exp $
5 //
6 // (C) Copyright 2000-2004 Werner Schweer (ws@seh.de)
7 // (C) Copyright 2011, 2016 Tim E. Real (terminator356 on sourceforge)
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 "track.h"
26 #include "event.h"
27 #include "midi_consts.h"
28 #include "mididev.h"
29 #include "song.h"
30 #include "audio.h"
31 #include "midictrl.h"
32 #include "helper.h"
33 #include "limits.h"
34 #include "dssihost.h"
35 #include "gconfig.h"
36 #include "operations.h"
37 #include "icons.h"
38
39 #include "drum_ordering.h"
40 #include "globals.h"
41 #include "config.h"
42
43 #include <QMessageBox>
44
45 // Forwards from header:
46 #include "midiport.h"
47 #include "plugin.h"
48 #include "xml.h"
49 #include "midiedit/drummap.h"
50 #include "minstrument.h"
51 #include "latency_compensator.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 namespace MusECore {
57
58 int Track::_snGen=0;
59
60 unsigned int Track::_soloRefCnt = 0;
61 Track* Track::_tmpSoloChainTrack = 0;
62 bool Track::_tmpSoloChainDoIns = false;
63 bool Track::_tmpSoloChainNoDec = false;
64 int Track::_selectionOrderCounter = 0;
65
66 const char* Track::_cname[] = {
67 "Midi", "Drum", "Wave",
68 "AudioOut", "AudioIn", "AudioGroup", "AudioAux", "AudioSynth"
69 };
70
71
72 bool MidiTrack::_isVisible=true;
73
74
75 //---------------------------------------------------------
76 // addPortCtrlEvents
77 //---------------------------------------------------------
78
addPortCtrlEvents(MidiTrack * t,bool drum_ctls,bool non_drum_ctls)79 void addPortCtrlEvents(MidiTrack* t, bool drum_ctls, bool non_drum_ctls)
80 {
81 if(!drum_ctls && !non_drum_ctls)
82 return;
83
84 bool is_drum_ctl;
85 const PartList* pl = t->cparts();
86 for(ciPart ip = pl->begin(); ip != pl->end(); ++ip)
87 {
88 Part* part = ip->second;
89 const EventList& el = part->events();
90 unsigned len = part->lenTick();
91 for(ciEvent ie = el.begin(); ie != el.end(); ++ie)
92 {
93 const Event& ev = ie->second;
94 // Do not add events which are past the end of the part.
95 #ifdef ALLOW_LEFT_HIDDEN_EVENTS
96 if((int)ev.tick() >= (int)len)
97 #else
98 if(ev.tick() >= len)
99 #endif
100 break;
101
102 #ifdef ALLOW_LEFT_HIDDEN_EVENTS
103 if((int)ev.tick() < 0)
104 continue;
105 #endif
106
107 if(ev.type() == Controller)
108 {
109 int tick = ev.tick() + part->tick();
110 int cntrl = ev.dataA();
111 int val = ev.dataB();
112
113 // Is it a drum controller event, according to the track port's instrument?
114 MidiPort* mp;
115 int ch;
116 is_drum_ctl = t->mappedPortChanCtrl(&cntrl, nullptr, &mp, &ch);
117
118 if((is_drum_ctl && drum_ctls) || (!is_drum_ctl && non_drum_ctls))
119 mp->setControllerVal(ch, tick, cntrl, val, part);
120 }
121 }
122 }
123 }
124
125 //---------------------------------------------------------
126 // removePortCtrlEvents
127 //---------------------------------------------------------
128
removePortCtrlEvents(MidiTrack * t,bool drum_ctls,bool non_drum_ctls)129 void removePortCtrlEvents(MidiTrack* t, bool drum_ctls, bool non_drum_ctls)
130 {
131 if(!drum_ctls && !non_drum_ctls)
132 return;
133
134 bool is_drum_ctl;
135 const PartList* pl = t->cparts();
136 for(ciPart ip = pl->begin(); ip != pl->end(); ++ip)
137 {
138 Part* part = ip->second;
139 const EventList& el = part->events();
140 for(ciEvent ie = el.begin(); ie != el.end(); ++ie)
141 {
142 const Event& ev = ie->second;
143
144 if(ev.type() == Controller)
145 {
146 int tick = ev.tick() + part->tick();
147 int cntrl = ev.dataA();
148 int val = ev.dataB();
149
150 // Is it a drum controller event, according to the track port's instrument?
151 MidiPort* mp;
152 int ch;
153 is_drum_ctl = t->mappedPortChanCtrl(&cntrl, nullptr, &mp, &ch);
154
155 if((is_drum_ctl && drum_ctls) || (!is_drum_ctl && non_drum_ctls))
156 mp->deleteController(ch, tick, cntrl, val, part);
157 }
158 }
159 }
160 }
161
162 //---------------------------------------------------------
163 // isVisible
164 //---------------------------------------------------------
isVisible()165 bool Track::isVisible()
166 {
167 switch (type())
168 {
169 case Track::AUDIO_AUX:
170 return AudioAux::visible();
171 case Track::AUDIO_GROUP:
172 return AudioGroup::visible();
173 case Track::AUDIO_INPUT:
174 return AudioInput::visible();
175 case Track::AUDIO_OUTPUT:
176 return AudioOutput::visible();
177 case Track::WAVE:
178 return WaveTrack::visible();
179 case Track::MIDI:
180 case Track::DRUM:
181 return MidiTrack::visible();
182 case Track::AUDIO_SOFTSYNTH:
183 return SynthI::visible();
184 default:
185 break;
186 }
187
188 return false;
189 }
190
191
192 //---------------------------------------------------------
193 // y
194 //---------------------------------------------------------
195
y() const196 int Track::y() const
197 {
198 TrackList* tl = MusEGlobal::song->tracks();
199 int yy = 0;
200 for (ciTrack it = tl->begin(); it != tl->end(); ++it) {
201 if (this == *it)
202 return yy;
203 yy += (*it)->height();
204 }
205 // FIXME Get this when loading a song with automation graphs showing. Benign. Likely song not fully loaded yet. p4.0.32
206 if(MusEGlobal::debugMsg)
207 printf("Track::y(%s): track not in tracklist\n", name().toLatin1().constData());
208 return -1;
209 }
210
211 //---------------------------------------------------------
212 // Track::init
213 //---------------------------------------------------------
214
init(int channels)215 void Track::init(int channels)
216 {
217 _auxRouteCount = 0;
218 _nodeTraversed = false;
219 _activity = 0;
220 _lastActivity = 0;
221 _recordFlag = false;
222 _mute = false;
223 _solo = false;
224 _internalSolo = 0;
225 _off = false;
226 _channels = channels; // 1 - mono, 2 - stereo
227 _selected = false;
228 _selectionOrder = 0;
229 _height = MusEGlobal::config.trackHeight;
230 _locked = false;
231 _recMonitor = false;
232 for (int i = 0; i < MusECore::MAX_CHANNELS; ++i) {
233 _meter[i] = 0.0;
234 _peak[i] = 0.0;
235 _isClipped[i] = false;
236 }
237 }
238
Track(Track::TrackType t,int channels)239 Track::Track(Track::TrackType t, int channels)
240 {
241 _type = t;
242 _sn = newSn();
243 init(channels);
244 }
245
Track(const Track & t,int flags)246 Track::Track(const Track& t, int flags)
247 {
248 _type = t.type();
249
250 // This should be reset for a copy of a track.
251 _sn = newSn();
252
253 init(t._channels);
254
255 // moved setting the unique name to Song::duplicateTracks()
256 // we'll see if there is any draw back to that.
257 // See comments in the header about naming copied tracks,
258 // and why we don't automatically pick a unique name.
259 _name = t.name();
260
261 internal_assign(t, flags | ASSIGN_PROPERTIES);
262 }
263
~Track()264 Track::~Track()
265 {
266 _parts.clearDelete();
267 }
268
269 //---------------------------------------------------------
270 // assign
271 //---------------------------------------------------------
272
assign(const Track & t,int flags)273 void Track::assign(const Track& t, int flags)
274 {
275 internal_assign(t, flags);
276 }
277
internal_assign(const Track & t,int flags)278 void Track::internal_assign(const Track& t, int flags)
279 {
280 if(flags & ASSIGN_PROPERTIES)
281 {
282 // Leave at init value. Should be set by adding routes later.
283 //_auxRouteCount = t._auxRouteCount;
284
285 // Leave at init value. Set by anti-circular routing mechanism later.
286 //_nodeTraversed = t._nodeTraversed;
287
288 // Leave at init value. (How can there be 'activity' yet on a new track?)
289 //_activity = t._activity;
290 //_lastActivity = t._lastActivity;
291
292 // Leave at init value. Likely we don't want the new track soloed,
293 // although there may be cases where we want that (such as modifying a
294 // track copy and then requesting the operations system switch tracks -
295 // in that case we likely want the solo to be the same). For now, caller
296 // can set afterwards. TODO Decide whether to copy it.
297 //_solo = t._solo;
298
299 // Leave at init value. Set by soloing and routing mechanisms later.
300 //_internalSolo = t._internalSolo;
301
302 // Leave at init value. Set by init().
303 //_channels = t._channels;
304
305 // Special for selected. Make sure this is called.
306 // NOTE This makes this track the most recent selected. TODO Try to leave
307 // the original track as the most recent selected. (More involved - the
308 // '_selected' members of all tracks would need to be re-indexed).
309 setSelected(t.selected());
310
311 // Leave at init value. Set by setSelected(), above.
312 //_selectionOrder = t.selectionOrder();
313
314 // For now, copy this. It may be set later.
315 _y = t._y;
316
317 // For now, copy this. The caller may set it to some other value after.
318 _height = t._height;
319
320 _off = t._off;
321 _recordFlag = t._recordFlag;
322 _mute = t._mute;
323 _comment = t.comment();
324 _locked = t.locked();
325 _recMonitor = t._recMonitor;
326 }
327 }
328
329 //---------------------------------------------------------
330 // trackTypeIcon
331 // Static
332 //---------------------------------------------------------
333
trackTypeIcon(TrackType type)334 QIcon* Track::trackTypeIcon(TrackType type)
335 {
336 switch(type) {
337 case MusECore::Track::MIDI:
338 return MusEGui::pianorollSVGIcon;
339 case MusECore::Track::DRUM:
340 return MusEGui::drumeditSVGIcon;
341 case MusECore::Track::WAVE:
342 return MusEGui::waveeditorSVGIcon;
343 case MusECore::Track::AUDIO_OUTPUT:
344 return MusEGui::trackOutputSVGIcon;
345 case MusECore::Track::AUDIO_INPUT:
346 return MusEGui::trackInputSVGIcon;
347 case MusECore::Track::AUDIO_GROUP:
348 return MusEGui::trackGroupVGIcon;
349 case MusECore::Track::AUDIO_AUX:
350 return MusEGui::trackAuxSVGIcon;
351 case MusECore::Track::AUDIO_SOFTSYNTH:
352 return MusEGui::synthSVGIcon;
353 }
354 return nullptr;
355 }
356
357 //---------------------------------------------------------
358 // trackTypeColor
359 // Static
360 //---------------------------------------------------------
361
trackTypeColor(TrackType type)362 QColor Track::trackTypeColor(TrackType type)
363 {
364 switch(type) {
365 case MusECore::Track::MIDI:
366 return MusEGlobal::config.midiTrackBg;
367 case MusECore::Track::DRUM:
368 return MusEGlobal::config.newDrumTrackBg;
369 case MusECore::Track::WAVE:
370 return MusEGlobal::config.waveTrackBg;
371 case MusECore::Track::AUDIO_OUTPUT:
372 return MusEGlobal::config.outputTrackBg;
373 case MusECore::Track::AUDIO_INPUT:
374 return MusEGlobal::config.inputTrackBg;
375 case MusECore::Track::AUDIO_GROUP:
376 return MusEGlobal::config.groupTrackBg;
377 case MusECore::Track::AUDIO_AUX:
378 return MusEGlobal::config.auxTrackBg;
379 case MusECore::Track::AUDIO_SOFTSYNTH:
380 return MusEGlobal::config.synthTrackBg;
381 default:
382 break;
383 }
384 return QColor();
385 }
386
387 //---------------------------------------------------------
388 // trackTypeLabelColor
389 // Static
390 //---------------------------------------------------------
391
trackTypeLabelColor(TrackType type)392 QColor Track::trackTypeLabelColor(TrackType type)
393 {
394 switch(type) {
395 case MusECore::Track::MIDI:
396 return MusEGlobal::config.midiTrackLabelBg;
397 case MusECore::Track::DRUM:
398 return MusEGlobal::config.newDrumTrackLabelBg;
399 case MusECore::Track::WAVE:
400 return MusEGlobal::config.waveTrackLabelBg;
401 case MusECore::Track::AUDIO_OUTPUT:
402 return MusEGlobal::config.outputTrackLabelBg;
403 case MusECore::Track::AUDIO_INPUT:
404 return MusEGlobal::config.inputTrackLabelBg;
405 case MusECore::Track::AUDIO_GROUP:
406 return MusEGlobal::config.groupTrackLabelBg;
407 case MusECore::Track::AUDIO_AUX:
408 return MusEGlobal::config.auxTrackLabelBg;
409 case MusECore::Track::AUDIO_SOFTSYNTH:
410 return MusEGlobal::config.synthTrackLabelBg;
411 default:
412 break;
413 }
414 return QColor();
415 }
416
417 //---------------------------------------------------------
418 // displayName
419 //---------------------------------------------------------
420
displayName() const421 QString Track::displayName() const
422 {
423 const int idx = MusEGlobal::song->tracks()->index(this);
424 return QString("%1:%2").arg(idx + 1).arg(_name);
425 }
426
427 //---------------------------------------------------------
428 // clearRecAutomation
429 //---------------------------------------------------------
430
clearRecAutomation(bool clearList)431 void Track::clearRecAutomation(bool clearList)
432 {
433 if(isMidiTrack())
434 return;
435 AudioTrack *t = static_cast<AudioTrack*>(this);
436 // Re-enable all track and plugin controllers, and synth controllers if applicable.
437 t->enableAllControllers();
438 if(clearList)
439 t->recEvents()->clear();
440 }
441
442 //---------------------------------------------------------
443 // setSelected
444 //---------------------------------------------------------
445
setSelected(bool f)446 void Track::setSelected(bool f)
447 {
448 if(f && !_selected)
449 _selectionOrder = _selectionOrderCounter++;
450 _selected = f;
451 }
452
453 //---------------------------------------------------------
454 // dump
455 //---------------------------------------------------------
456
dump() const457 void Track::dump() const
458 {
459 printf("Track <%s>: typ %d, parts %zd sel %d sel order%d\n",
460 _name.toLatin1().constData(), _type, _parts.size(), _selected, _selectionOrder);
461 }
462
463 //---------------------------------------------------------
464 // updateAuxRoute
465 // Internal use. Update all the Aux ref counts of tracks dst is connected to.
466 // If dst is valid, start traversal from there, not from this track.
467 //---------------------------------------------------------
468
updateAuxRoute(int refInc,Track * dst)469 void Track::updateAuxRoute(int refInc, Track* dst)
470 {
471 if(isMidiTrack())
472 return;
473
474 if(dst)
475 {
476 _nodeTraversed = true;
477 dst->updateAuxRoute(refInc, NULL);
478 _nodeTraversed = false;
479 return;
480 }
481
482 if(_type == AUDIO_AUX)
483 return;
484
485 if(_nodeTraversed)
486 {
487 fprintf(stderr, "Track::updateAuxRoute %s _auxRouteCount:%d refInc:%d :\n", name().toLatin1().constData(), _auxRouteCount, refInc);
488 if(refInc >= 0)
489 fprintf(stderr, " MusE Warning: Please check your routes: Circular path found!\n");
490 else
491 fprintf(stderr, " MusE: Circular path removed.\n");
492 return;
493 }
494
495 _nodeTraversed = true;
496
497 _auxRouteCount += refInc;
498 if(_auxRouteCount < 0)
499 {
500 fprintf(stderr, "Track::updateAuxRoute Ref underflow! %s _auxRouteCount:%d refInc:%d\n", name().toLatin1().constData(), _auxRouteCount, refInc);
501 }
502
503 for (iRoute i = _outRoutes.begin(); i != _outRoutes.end(); ++i)
504 {
505 if( !(*i).isValid() || (*i).type != Route::TRACK_ROUTE )
506 continue;
507 Track* t = (*i).track;
508 t->updateAuxRoute(refInc, NULL);
509 }
510
511 _nodeTraversed = false;
512 }
513
514 //---------------------------------------------------------
515 // isCircularRoute
516 // If dst is valid, start traversal from there, not from this track.
517 // Returns true if circular.
518 //---------------------------------------------------------
519
isCircularRoute(Track * dst)520 bool Track::isCircularRoute(Track* dst)
521 {
522 bool rv = false;
523
524 if(dst)
525 {
526 _nodeTraversed = true;
527 rv = dst->isCircularRoute(NULL);
528 _nodeTraversed = false;
529 return rv;
530 }
531
532 if(_nodeTraversed)
533 return true;
534
535 _nodeTraversed = true;
536
537 for (iRoute i = _outRoutes.begin(); i != _outRoutes.end(); ++i)
538 {
539 if( !(*i).isValid() || (*i).type != Route::TRACK_ROUTE )
540 continue;
541 Track* t = (*i).track;
542 rv = t->isCircularRoute(NULL);
543 if(rv)
544 break;
545 }
546
547 _nodeTraversed = false;
548 return rv;
549 }
550
routeCapabilities() const551 RouteCapabilitiesStruct Track::routeCapabilities() const
552 {
553 RouteCapabilitiesStruct s;
554 s._trackChannels._inChannels = s._trackChannels._outChannels = _channels;
555 s._trackChannels._inRoutable = s._trackChannels._outRoutable = (_channels != 0);
556 return s;
557 }
558
canDominateOutputLatency() const559 inline bool Track::canDominateOutputLatency() const
560 {
561 // Return true only if the track is on and the user wants unterminated branches counted.
562 return !off() && MusEGlobal::config.correctUnterminatedOutBranchLatency;
563 }
564
canDominateInputLatency() const565 inline bool Track::canDominateInputLatency() const
566 {
567 return false;
568 }
569
canPassThruLatency() const570 bool Track::canPassThruLatency() const
571 {
572 return !off() &&
573 (!canRecordMonitor() ||
574 (MusEGlobal::config.monitoringAffectsLatency &&
575 isRecMonitored())); // || recordFlag();
576 }
577
prepareLatencyScan()578 void Track::prepareLatencyScan() {
579 _latencyInfo.initialize();
580 _transportSource.prepareLatencyScan(transportAffectsAudioLatency());
581 }
582
getWorstPluginLatencyAudio()583 float Track::getWorstPluginLatencyAudio()
584 {
585 // Have we been here before during this scan?
586 // Just return the cached value.
587 if(_latencyInfo._worstPluginLatencyProcessed)
588 return _latencyInfo._worstPluginLatency;
589
590 _latencyInfo._worstPluginLatency = 0.0f;
591 _latencyInfo._worstPluginLatencyProcessed = true;
592 return _latencyInfo._worstPluginLatency;
593 }
594
getWorstPortLatencyAudio()595 float Track::getWorstPortLatencyAudio()
596 {
597 // Have we been here before during this scan?
598 // Just return the cached value.
599 if(_latencyInfo._worstPortLatencyProcessed)
600 return _latencyInfo._worstPortLatency;
601
602 _latencyInfo._worstPortLatency = 0.0f;
603 _latencyInfo._worstPortLatencyProcessed = true;
604 return _latencyInfo._worstPortLatency;
605 }
606
getWorstSelfLatencyAudio()607 float Track::getWorstSelfLatencyAudio()
608 {
609 // Have we been here before during this scan?
610 // Just return the cached value.
611 if(_latencyInfo._worstSelfLatencyProcessed)
612 return _latencyInfo._worstSelfLatency;
613
614 _latencyInfo._worstSelfLatency = 0.0f;
615 _latencyInfo._worstSelfLatencyProcessed = true;
616 return _latencyInfo._worstSelfLatency;
617 }
618
619 //---------------------------------------------------------
620 // MidiTrack
621 //---------------------------------------------------------
622
MidiTrack()623 MidiTrack::MidiTrack()
624 : Track(MIDI)
625 {
626 init();
627
628 _drummap=new DrumMap[128];
629 _workingDrumMapPatchList = new WorkingDrumMapPatchList();
630
631 init_drummap(true /* write drummap ordering information as well */);
632 }
633
MidiTrack(const MidiTrack & mt,int flags)634 MidiTrack::MidiTrack(const MidiTrack& mt, int flags)
635 : Track(mt, flags)
636 {
637 init();
638
639 _drummap=new DrumMap[128];
640 _workingDrumMapPatchList = new WorkingDrumMapPatchList();
641
642 internal_assign(mt, flags | Track::ASSIGN_PROPERTIES);
643 }
644
internal_assign(const Track & t,int flags)645 void MidiTrack::internal_assign(const Track& t, int flags)
646 {
647 if(!t.isMidiTrack())
648 return;
649
650 const MidiTrack& mt = (const MidiTrack&)t;
651
652 if(flags & ASSIGN_PROPERTIES)
653 {
654 _outPort = mt.outPort();
655 _outChannel = mt.outChannel();
656 transposition = mt.transposition;
657 velocity = mt.velocity;
658 delay = mt.delay;
659 len = mt.len;
660 compression = mt.compression;
661 clefType = mt.clefType;
662 _curDrumPatchNumber = mt._curDrumPatchNumber;
663 }
664
665 if(flags & ASSIGN_ROUTES)
666 {
667 for(ciRoute ir = mt._inRoutes.begin(); ir != mt._inRoutes.end(); ++ir)
668 // Don't call msgAddRoute. Caller later calls msgAddTrack which 'mirrors' this routing node.
669 _inRoutes.push_back(*ir);
670
671 for(ciRoute ir = mt._outRoutes.begin(); ir != mt._outRoutes.end(); ++ir)
672 // Don't call msgAddRoute. Caller later calls msgAddTrack which 'mirrors' this routing node.
673 _outRoutes.push_back(*ir);
674 }
675 else if(flags & ASSIGN_DEFAULT_ROUTES)
676 {
677 // Add default track <-> midiport routes.
678 int c;
679 bool defOutFound = false; /// TODO: Remove this if and when multiple output routes supported.
680 const int chmask = (1 << MusECore::MUSE_MIDI_CHANNELS) - 1;
681 for(int i = 0; i < MusECore::MIDI_PORTS; ++i)
682 {
683 MidiPort* mp = &MusEGlobal::midiPorts[i];
684
685 if(mp->device()) // Only if device is valid.
686 {
687 c = mp->defaultInChannels();
688 if(c)
689 {
690 // Don't call msgAddRoute. Caller later calls msgAddTrack which 'mirrors' this routing node.
691 // All channels set or Omni? Use an Omni route:
692 if(c == -1 || c == chmask)
693 _inRoutes.push_back(Route(i));
694 else
695 // Add individual channels:
696 for(int ch = 0; ch < MusECore::MUSE_MIDI_CHANNELS; ++ch)
697 {
698 if(c & (1 << ch))
699 _inRoutes.push_back(Route(i, ch));
700 }
701 }
702 }
703
704 if(!defOutFound)
705 {
706 c = mp->defaultOutChannels();
707 if(c)
708 {
709
710 #ifdef _USE_MIDI_TRACK_SINGLE_OUT_PORT_CHAN_
711 if(c == -1)
712 c = 1; // Just to be safe, shouldn't happen, default to channel 0.
713 for(int ch = 0; ch < MusECore::MUSE_MIDI_CHANNELS; ++ch)
714 {
715 if(c & (1 << ch))
716 {
717 defOutFound = true;
718 _outPort = i;
719 // Leave drum tracks at channel 10. TODO: Want this?
720 //if(type() != Track::NEW_DRUM)
721 _outChannel = ch;
722 break;
723 }
724 }
725 #else
726 // All channels set or Omni? Use an Omni route:
727 if(c == -1 || c == chmask)
728 _outRoutes.push_back(Route(i));
729 else
730 // Add individual channels:
731 for(int ch = 0; ch < MusECore::MUSE_MIDI_CHANNELS; ++ch)
732 {
733 if(c & (1 << ch))
734 _outRoutes.push_back(Route(i, ch));
735 }
736
737 #endif
738
739 }
740 }
741 }
742 }
743
744 if (flags & ASSIGN_DRUMLIST)
745 {
746 // Safety in case assignment called on an existing track which is already in global_drum_ordering.
747 remove_ourselves_from_drum_ordering();
748
749 for (MusEGlobal::global_drum_ordering_t::iterator it=MusEGlobal::global_drum_ordering.begin();
750 it!=MusEGlobal::global_drum_ordering.end(); ++it)
751 {
752 if (it->first == &mt)
753 {
754 // duplicates the entry at it, set it to the first entry of both
755 it=MusEGlobal::global_drum_ordering.insert(it, *it);
756 // make it point to the second entry
757 ++it;
758 it->first=this;
759 }
760 }
761
762 for (int i=0;i<128;i++) // no memcpy allowed here. dunno exactly why,
763 _drummap[i]=mt._drummap[i]; // seems QString-related.
764 update_drum_in_map();
765 _drummap_ordering_tied_to_patch=mt._drummap_ordering_tied_to_patch;
766 // TODO FINDMICH "assign" ordering as well
767
768 if(mt._workingDrumMapPatchList)
769 *_workingDrumMapPatchList = *mt._workingDrumMapPatchList;
770 }
771 else
772 {
773 init_drummap(true /* write drummap ordering information as well */);
774 }
775
776 const bool dup = flags & ASSIGN_DUPLICATE_PARTS;
777 const bool cpy = flags & ASSIGN_COPY_PARTS;
778 const bool cln = flags & ASSIGN_CLONE_PARTS;
779 if(dup || cpy || cln)
780 {
781 const PartList* pl = t.cparts();
782 for (ciPart ip = pl->begin(); ip != pl->end(); ++ip) {
783 Part* spart = ip->second;
784 Part* dpart = 0;
785 if(dup)
786 dpart = spart->hasClones() ? spart->createNewClone() : spart->duplicate();
787 else if(cpy)
788 dpart = spart->duplicate();
789 else if(cln)
790 dpart = spart->createNewClone();
791 if(dpart)
792 {
793 dpart->setTrack(this);
794 parts()->add(dpart);
795 }
796 }
797 }
798
799 }
800
assign(const Track & t,int flags)801 void MidiTrack::assign(const Track& t, int flags)
802 {
803 Track::assign(t, flags);
804 internal_assign(t, flags);
805 }
806
~MidiTrack()807 MidiTrack::~MidiTrack()
808 {
809 if(_workingDrumMapPatchList)
810 delete _workingDrumMapPatchList;
811 delete [] _drummap;
812 remove_ourselves_from_drum_ordering();
813 }
814
815
setRecordFlag2AndCheckMonitor(bool f)816 bool MidiTrack::setRecordFlag2AndCheckMonitor(bool f)
817 {
818 if(canRecord())
819 _recordFlag = f;
820
821 if(MusEGlobal::config.monitorOnRecord && canRecordMonitor())
822 {
823 if(f != _recMonitor)
824 {
825 _recMonitor = f;
826 return true;
827 }
828 }
829 return false;
830 }
831
convertToType(TrackType trackType)832 void MidiTrack::convertToType(TrackType trackType)
833 {
834 if(trackType == MusECore::Track::MIDI || trackType == MusECore::Track::DRUM)
835 {
836 //
837 // Drum -> Midi
838 //
839 MusECore::PartList* pl = parts();
840 for (MusECore::iPart ip = pl->begin(); ip != pl->end(); ++ip) {
841 for (MusECore::ciEvent ie = ip->second->events().begin(); ie != ip->second->events().end(); ++ie) {
842 MusECore::Event ev = ie->second;
843 if(ev.type() == MusECore::Note)
844 {
845 int pitch = ev.pitch();
846 pitch = MusEGlobal::drumMap[pitch].enote;
847 ev.setPitch(pitch);
848 }
849 else
850 if(ev.type() == MusECore::Controller)
851 {
852 int ctl = ev.dataA();
853 // Is it a drum controller event, according to the track port's instrument?
854 MusECore::MidiController *mc = MusEGlobal::midiPorts[outPort()].drumController(ctl);
855 if(mc)
856 // Change the controller event's index into the drum map to an instrument note.
857 ev.setA((ctl & ~0xff) | MusEGlobal::drumMap[ctl & 0x7f].enote);
858 }
859 }
860 }
861 setType(trackType);
862 }
863 }
864
remove_ourselves_from_drum_ordering()865 void MidiTrack::remove_ourselves_from_drum_ordering()
866 {
867 for (MusEGlobal::global_drum_ordering_t::iterator it=MusEGlobal::global_drum_ordering.begin(); it!=MusEGlobal::global_drum_ordering.end();)
868 if (it->first == this)
869 it=MusEGlobal::global_drum_ordering.erase(it);
870 else
871 it++;
872 }
873
874 //---------------------------------------------------------
875 // init
876 //---------------------------------------------------------
877
init()878 void MidiTrack::init()
879 {
880 _outPort = 0;
881
882 // let's set the port to the last instantiated device
883 // if midi-channel defaults are set in the configuration it
884 // will override this setting
885 for (int i = MusECore::MIDI_PORTS - 1; i > -1; i--)
886 {
887 if (MusEGlobal::midiPorts[i].device() != NULL)
888 {
889 _outPort = i;
890 break;
891 }
892 }
893
894 _outChannel = (type()==DRUM) ? 9 : 0;
895
896 clefType=trebleClef;
897
898 _curDrumPatchNumber = CTRL_VAL_UNKNOWN;
899
900 transposition = 0;
901 velocity = 0;
902 delay = 0;
903 len = 100; // percent
904 compression = 100; // percent
905 }
906
init_drum_ordering()907 void MidiTrack::init_drum_ordering()
908 {
909 // first display entries with non-empty names, then with empty names.
910
911 remove_ourselves_from_drum_ordering();
912
913 for (int i=0;i<128;i++)
914 if (_drummap[i].name!="" && _drummap[i].name!="?") // non-empty name?
915 MusEGlobal::global_drum_ordering.push_back(std::pair<MidiTrack*,int>(this,i));
916
917 for (int i=0;i<128;i++)
918 if (!(_drummap[i].name!="" && _drummap[i].name!="?")) // empty name?
919 MusEGlobal::global_drum_ordering.push_back(std::pair<MidiTrack*,int>(this,i));
920 }
921
init_drummap(bool write_ordering)922 void MidiTrack::init_drummap(bool write_ordering)
923 {
924 for (int i=0;i<128;i++)
925 _drummap[i]=iNewDrumMap[i];
926
927 if (write_ordering)
928 init_drum_ordering();
929
930 update_drum_in_map();
931
932 _drummap_ordering_tied_to_patch=true;
933 }
934
update_drum_in_map()935 void MidiTrack::update_drum_in_map()
936 {
937 for (int i = 0; i < 128; ++i)
938 drum_in_map[(int)_drummap[i].enote] = i;
939 }
940
941 //---------------------------------------------------------
942 // height
943 //---------------------------------------------------------
height() const944 int MidiTrack::height() const
945 {
946 if (_isVisible)
947 return _height;
948 return 0;
949 }
950
951 //---------------------------------------------------------
952 // routeCapabilities
953 //---------------------------------------------------------
954
routeCapabilities() const955 RouteCapabilitiesStruct MidiTrack::routeCapabilities() const
956 {
957 RouteCapabilitiesStruct s;
958 s._midiPortChannels._inRoutable = true;
959 s._midiPortChannels._inChannels = MusECore::MUSE_MIDI_CHANNELS;
960 s._trackChannels._outRoutable = true; // Support Midi Track to Audio Input Track routes (for soloing chain).
961
962 #ifndef _USE_MIDI_TRACK_SINGLE_OUT_PORT_CHAN_
963 s._midiPortChannels._outChannels = MusECore::MUSE_MIDI_CHANNELS;
964 #endif
965
966 return s;
967 }
968
969 //---------------------------------------------------------
970 // canDominateOutputLatency
971 //---------------------------------------------------------
972
canDominateOutputLatency() const973 inline bool MidiTrack::canDominateOutputLatency() const
974 {
975 // The midi track's own midi file contributions can never dominate latency.
976 return false;
977 }
978
canCorrectOutputLatency() const979 inline bool MidiTrack::canCorrectOutputLatency() const
980 {
981 return true;
982 }
983
isLatencyInputTerminal()984 bool MidiTrack::isLatencyInputTerminal()
985 {
986 // Have we been here before during this scan?
987 // Just return the cached value.
988 if(_latencyInfo._isLatencyInputTerminalProcessed)
989 return _latencyInfo._isLatencyInputTerminal;
990
991 // If we're asking for the view from the record side, check if we're
992 // passing the signal through the track via monitoring.
993 if(!canPassThruLatency())
994 {
995 _latencyInfo._isLatencyInputTerminal = true;
996 _latencyInfo._isLatencyInputTerminalProcessed = true;
997 return true;
998 }
999
1000 #ifdef _USE_MIDI_TRACK_SINGLE_OUT_PORT_CHAN_
1001 const int port = outPort();
1002 if(port >= 0 && port < MusECore::MIDI_PORTS)
1003 {
1004 MidiPort* mp = &MusEGlobal::midiPorts[port];
1005 MidiDevice* md = mp->device();
1006 if(md && (md->openFlags() & 1 /*write*/))
1007 {
1008 // If it's a non-synth device, or a synth that is not off.
1009 if(!md->isSynti() || !static_cast<SynthI*>(md)->off())
1010 {
1011 _latencyInfo._isLatencyInputTerminal = false;
1012 _latencyInfo._isLatencyInputTerminalProcessed = true;
1013 return false;
1014 }
1015 }
1016 }
1017
1018 #else
1019
1020 const RouteList* rl = outRoutes();
1021 for (ciRoute ir = rl->begin(); ir != rl->end(); ++ir) {
1022 switch(ir->type)
1023 {
1024 case Route::MIDI_PORT_ROUTE:
1025 {
1026 const int port = ir->midiPort;
1027 const int ch = ir->channel;
1028 if(port < 0 || port >= MusECore::MIDI_PORTS || ch < -1 || ch >= MusECore::MUSE_MIDI_CHANNELS)
1029 continue;
1030
1031 MidiPort* mp = &MusEGlobal::midiPorts[ir->midiPort];
1032 MidiDevice* md = mp->device();
1033 if(!md)
1034 continue;
1035
1036 if(md->openFlags() & 1 /*write*/)
1037 {
1038 _latencyInfo._isLatencyInputTerminal = false;
1039 _latencyInfo._isLatencyInputTerminalProcessed = true;
1040 return false;
1041 }
1042 }
1043 break;
1044
1045 case Route::TRACK_ROUTE:
1046 if(!ir->track)
1047 continue;
1048 if(ir->track->isMidiTrack())
1049 {
1050 // TODO
1051 }
1052 break;
1053
1054 default:
1055 break;
1056 }
1057 }
1058
1059 #endif
1060
1061 _latencyInfo._isLatencyInputTerminal = true;
1062 _latencyInfo._isLatencyInputTerminalProcessed = true;
1063 return true;
1064 }
1065
isLatencyOutputTerminal()1066 bool MidiTrack::isLatencyOutputTerminal()
1067 {
1068 // Have we been here before during this scan?
1069 // Just return the cached value.
1070 if(_latencyInfo._isLatencyOutputTerminalProcessed)
1071 return _latencyInfo._isLatencyOutputTerminal;
1072
1073 #ifdef _USE_MIDI_TRACK_SINGLE_OUT_PORT_CHAN_
1074 const int port = outPort();
1075 //if((openFlags() & (capture ? 2 : 1)) && port >= 0 && port < MusECore::MIDI_PORTS)
1076 //if((openFlags() & 1 /*write*/) && port >= 0 && port < MusECore::MIDI_PORTS)
1077 if(port >= 0 && port < MusECore::MIDI_PORTS)
1078 {
1079 MidiPort* mp = &MusEGlobal::midiPorts[port];
1080 MidiDevice* md = mp->device();
1081 if(md && (md->openFlags() & 1 /*write*/))
1082 {
1083 // If it's a non-synth device, or a synth that is not off.
1084 if(!md->isSynti() || !static_cast<SynthI*>(md)->off())
1085 {
1086 _latencyInfo._isLatencyOutputTerminal = false;
1087 _latencyInfo._isLatencyOutputTerminalProcessed = true;
1088 return false;
1089 }
1090 }
1091 }
1092
1093 #else
1094
1095 const RouteList* rl = outRoutes();
1096 for (ciRoute ir = rl->begin(); ir != rl->end(); ++ir) {
1097 switch(ir->type)
1098 {
1099 case Route::MIDI_PORT_ROUTE:
1100 {
1101 const int port = ir->midiPort;
1102 const int ch = ir->channel;
1103 if(port < 0 || port >= MusECore::MIDI_PORTS || ch < -1 || ch >= MusECore::MUSE_MIDI_CHANNELS)
1104 continue;
1105
1106 MidiPort* mp = &MusEGlobal::midiPorts[ir->midiPort];
1107 MidiDevice* md = mp->device();
1108 if(!md)
1109 continue;
1110
1111 if(md->openFlags() & 1 /*write*/)
1112 {
1113 _latencyInfo._isLatencyOutputTerminal = false;
1114 _latencyInfo._isLatencyOutputTerminalProcessed = true;
1115 return false;
1116 }
1117 }
1118 break;
1119
1120 case Route::TRACK_ROUTE:
1121 if(!ir->track)
1122 continue;
1123 if(ir->track->isMidiTrack())
1124 {
1125 // TODO
1126 }
1127 break;
1128
1129 default:
1130 break;
1131 }
1132 }
1133
1134 #endif
1135
1136 _latencyInfo._isLatencyOutputTerminal = true;
1137 _latencyInfo._isLatencyOutputTerminalProcessed = true;
1138 return true;
1139 }
1140
1141 //---------------------------------------------------------
1142 // getDominanceInfo
1143 //---------------------------------------------------------
1144
getDominanceInfo(bool input)1145 TrackLatencyInfo& MidiTrack::getDominanceInfo(bool input)
1146 {
1147 // Have we been here before during this scan?
1148 // Just return the cached value.
1149 if((input && _latencyInfo._canDominateInputProcessed) ||
1150 (!input && _latencyInfo._canDominateProcessed))
1151 return _latencyInfo;
1152
1153 // Get the default domination for this track type.
1154 bool can_dominate_lat = input ? canDominateInputLatency() : canDominateOutputLatency();
1155 bool can_correct_lat = canCorrectOutputLatency();
1156
1157 const bool passthru = canPassThruLatency();
1158
1159 // Gather latency info from all connected input branches,
1160 // but ONLY if the track is not off.
1161 bool item_found = false;
1162
1163 if(!off() && (passthru || input))
1164 {
1165 RouteList* rl = inRoutes();
1166 for (iRoute ir = rl->begin(); ir != rl->end(); ++ir)
1167 {
1168 switch(ir->type)
1169 {
1170 case Route::MIDI_PORT_ROUTE:
1171 {
1172 const int port = ir->midiPort;
1173 const int ch = ir->channel;
1174 if(port < 0 || port >= MusECore::MIDI_PORTS || ch < -1 || ch >= MusECore::MUSE_MIDI_CHANNELS)
1175 continue;
1176
1177 MidiPort* mp = &MusEGlobal::midiPorts[ir->midiPort];
1178 MidiDevice* md = mp->device();
1179 if(!md)
1180 continue;
1181
1182 //if(!off() && (md->openFlags() & 2 /*read*/) && (passthru || input))
1183 if(md->openFlags() & 2 /*read*/)
1184 {
1185 const TrackLatencyInfo& li = md->getDominanceInfoMidi(true /*capture*/, false);
1186
1187 // Whether the branch can dominate or correct latency or if we
1188 // want to allow unterminated input branches to
1189 // participate in worst branch latency calculations.
1190 const bool participate =
1191 (li._canCorrectOutputLatency ||
1192 li._canDominateOutputLatency ||
1193 MusEGlobal::config.correctUnterminatedInBranchLatency);
1194
1195 if(participate)
1196 {
1197 // Is it the first found item?
1198 if(item_found)
1199 {
1200 // If any one of the branches can dominate the latency,
1201 // that overrides any which cannot.
1202 if(li._canDominateOutputLatency)
1203 can_dominate_lat = true;
1204 if(li._canCorrectOutputLatency)
1205 can_correct_lat = true;
1206 }
1207 else
1208 {
1209 item_found = true;
1210 // Override the defaults with this first item's values.
1211 //route_worst_out_corr = li._outputAvailableCorrection;
1212 can_dominate_lat = li._canDominateOutputLatency;
1213 can_correct_lat = li._canCorrectOutputLatency;
1214 }
1215 }
1216 }
1217 }
1218 break;
1219
1220 case Route::TRACK_ROUTE:
1221 if(!ir->track)
1222 continue;
1223 if(ir->track->isMidiTrack())
1224 {
1225 // TODO
1226 }
1227 break;
1228
1229 default:
1230 break;
1231 }
1232 }
1233 }
1234
1235 // Set the correction of all connected input branches,
1236 // but ONLY if the track is not off.
1237 if(!off())
1238 {
1239 if(input)
1240 {
1241 _latencyInfo._canDominateInputLatency = can_dominate_lat;
1242 }
1243 else
1244 {
1245 _latencyInfo._canDominateOutputLatency = can_dominate_lat;
1246 // If any of the branches can dominate, then this node cannot correct.
1247 _latencyInfo._canCorrectOutputLatency = can_correct_lat && !can_dominate_lat;
1248 }
1249 }
1250
1251 if(input)
1252 _latencyInfo._canDominateInputProcessed = true;
1253 else
1254 _latencyInfo._canDominateProcessed = true;
1255
1256 return _latencyInfo;
1257 }
1258
1259 //---------------------------------------------------------
1260 // getDominanceLatencyInfo
1261 //---------------------------------------------------------
1262
getDominanceLatencyInfo(bool input)1263 TrackLatencyInfo& MidiTrack::getDominanceLatencyInfo(bool input)
1264 {
1265 // Have we been here before during this scan?
1266 // Just return the cached value.
1267 if((input && _latencyInfo._dominanceInputProcessed) ||
1268 (!input && _latencyInfo._dominanceProcessed))
1269 return _latencyInfo;
1270
1271 float route_worst_latency = 0.0f;
1272
1273 const bool passthru = canPassThruLatency();
1274
1275 bool item_found = false;
1276
1277 float worst_self_latency = 0.0f;
1278 if(!input && !off())
1279 worst_self_latency = getWorstSelfLatencyAudio();
1280
1281 if(!off() && (passthru || input))
1282 {
1283 RouteList* rl = inRoutes();
1284 for (iRoute ir = rl->begin(); ir != rl->end(); ++ir)
1285 {
1286 switch(ir->type)
1287 {
1288 case Route::MIDI_PORT_ROUTE:
1289 {
1290 const int port = ir->midiPort;
1291 const int ch = ir->channel;
1292 if(port < 0 || port >= MusECore::MIDI_PORTS || ch < -1 || ch >= MusECore::MUSE_MIDI_CHANNELS)
1293 continue;
1294
1295 MidiPort* mp = &MusEGlobal::midiPorts[ir->midiPort];
1296 MidiDevice* md = mp->device();
1297 if(!md)
1298 continue;
1299
1300 //if(!off() && (md->openFlags() & 2 /*read*/) && (passthru || input))
1301 if(md->openFlags() & 2 /*read*/)
1302 {
1303 const TrackLatencyInfo& li = md->getDominanceLatencyInfoMidi(true /*capture*/, false);
1304
1305 // Whether the branch can dominate or correct latency or if we
1306 // want to allow unterminated input branches to
1307 // participate in worst branch latency calculations.
1308 const bool participate =
1309 (li._canCorrectOutputLatency ||
1310 li._canDominateOutputLatency ||
1311 MusEGlobal::config.correctUnterminatedInBranchLatency);
1312
1313 if(participate)
1314 {
1315 // Is it the first found item?
1316 if(item_found)
1317 {
1318 // If any one of the branches can dominate the latency,
1319 // that overrides any which cannot.
1320 if(li._canDominateOutputLatency)
1321 {
1322 // Override the current worst value if the latency is greater,
1323 // but ONLY if the branch can dominate.
1324 //if(li._outputLatency > route_worst_latency)
1325 // route_worst_latency = li._outputLatency;
1326 }
1327 // Override the current worst value if the latency is greater,
1328 // but ONLY if the branch can dominate.
1329 if(li._outputLatency > route_worst_latency)
1330 route_worst_latency = li._outputLatency;
1331 }
1332 else
1333 {
1334 item_found = true;
1335 // Override the default worst value, but ONLY if the branch can dominate.
1336 //if(li._canDominateOutputLatency)
1337 route_worst_latency = li._outputLatency;
1338 }
1339 }
1340 }
1341 }
1342 break;
1343
1344 case Route::TRACK_ROUTE:
1345 if(!ir->track)
1346 continue;
1347 if(ir->track->isMidiTrack())
1348 {
1349 // TODO
1350 }
1351 break;
1352
1353 default:
1354 break;
1355 }
1356 }
1357 }
1358
1359 // Set the correction of all connected input branches,
1360 // but ONLY if the track is not off.
1361 if(!off())
1362 {
1363 if(input)
1364 {
1365 _latencyInfo._inputLatency = route_worst_latency;
1366 }
1367 else
1368 {
1369 if(passthru)
1370 {
1371 _latencyInfo._outputLatency = worst_self_latency + route_worst_latency;
1372 _latencyInfo._inputLatency = route_worst_latency;
1373 }
1374 else
1375 {
1376 _latencyInfo._outputLatency = worst_self_latency + _latencyInfo._sourceCorrectionValue;
1377 }
1378 }
1379 }
1380
1381 if(input)
1382 _latencyInfo._dominanceInputProcessed = true;
1383 else
1384 _latencyInfo._dominanceProcessed = true;
1385
1386 return _latencyInfo;
1387 }
1388
1389 //---------------------------------------------------------
1390 // setCorrectionLatencyInfo
1391 //---------------------------------------------------------
1392
setCorrectionLatencyInfo(bool input,float finalWorstLatency,float callerBranchLatency)1393 TrackLatencyInfo& MidiTrack::setCorrectionLatencyInfo(bool input, float finalWorstLatency, float callerBranchLatency)
1394 {
1395 const bool passthru = canPassThruLatency();
1396
1397 float worst_self_latency = 0.0f;
1398 if(!input && !off())
1399 worst_self_latency = getWorstSelfLatencyAudio();
1400
1401 // The _trackLatency should already be calculated in the dominance scan.
1402 const float branch_lat = callerBranchLatency + worst_self_latency;
1403
1404 if(!off() && (passthru || input))
1405 {
1406 RouteList* rl = inRoutes();
1407 for (iRoute ir = rl->begin(); ir != rl->end(); ++ir)
1408 {
1409 switch(ir->type)
1410 {
1411 case Route::MIDI_PORT_ROUTE:
1412 {
1413 if(ir->midiPort < 0 || ir->midiPort >= MusECore::MIDI_PORTS ||
1414 ir->channel < -1 || ir->channel >= MusECore::MUSE_MIDI_CHANNELS)
1415 continue;
1416 const MidiPort* mp = &MusEGlobal::midiPorts[ir->midiPort];
1417 MidiDevice* md = mp->device();
1418
1419 //if(!off() && md && (md->openFlags() & 2 /*read*/) && (passthru || input))
1420 if(md && (md->openFlags() & 2 /*read*/))
1421 md->setCorrectionLatencyInfoMidi(true /*capture*/, false, finalWorstLatency, branch_lat);
1422 }
1423 break;
1424
1425 default:
1426 break;
1427 }
1428 }
1429 }
1430
1431 // Set the correction of all connected input branches,
1432 // but ONLY if the track is not off.
1433 if(!off())
1434 {
1435 if(input)
1436 {
1437 }
1438 else
1439 {
1440 if(canCorrectOutputLatency() && _latencyInfo._canCorrectOutputLatency)
1441 {
1442 float corr = 0.0f;
1443 if(MusEGlobal::config.commonProjectLatency)
1444 corr -= finalWorstLatency;
1445
1446 corr -= branch_lat;
1447 // The _sourceCorrectionValue is initialized to zero.
1448 // Whichever calling branch needs the most correction gets it.
1449 if(corr < _latencyInfo._sourceCorrectionValue)
1450 _latencyInfo._sourceCorrectionValue = corr;
1451 }
1452 }
1453
1454 //fprintf(stderr, "MidiTrack::setCorrectionLatencyInfo() name:%s finalWorstLatency:%f branch_lat:%f corr:%f _sourceCorrectionValue:%f\n",
1455 // name().toLatin1().constData(), finalWorstLatency, branch_lat, corr, _latencyInfo._sourceCorrectionValue);
1456 }
1457
1458 return _latencyInfo;
1459 }
1460
1461 //---------------------------------------------------------
1462 // getLatencyInfo
1463 //---------------------------------------------------------
1464
getLatencyInfo(bool input)1465 TrackLatencyInfo& MidiTrack::getLatencyInfo(bool input)
1466 {
1467 // Have we been here before during this scan?
1468 // Just return the cached value.
1469 if((input && _latencyInfo._inputProcessed) ||
1470 (!input && _latencyInfo._processed))
1471 return _latencyInfo;
1472
1473 float route_worst_latency = _latencyInfo._inputLatency;
1474
1475 const bool passthru = canPassThruLatency();
1476
1477 RouteList* rl = inRoutes();
1478
1479 // Now that we know the worst-case latency of the connected branches,
1480 // adjust each of the conveniently stored temporary latency values
1481 // in the routes according to whether they can dominate...
1482 for (iRoute ir = rl->begin(); ir != rl->end(); ++ir)
1483 {
1484 switch(ir->type)
1485 {
1486 case Route::MIDI_PORT_ROUTE:
1487 {
1488 const int port = ir->midiPort;
1489 const int ch = ir->channel;
1490 if(port < 0 || port >= MusECore::MIDI_PORTS || ch < -1 || ch >= MusECore::MUSE_MIDI_CHANNELS)
1491 continue;
1492
1493 MidiPort* mp = &MusEGlobal::midiPorts[ir->midiPort];
1494 MidiDevice* md = mp->device();
1495 if(!md)
1496 continue;
1497
1498 if(passthru || input)
1499 {
1500 // Default to zero.
1501 ir->audioLatencyOut = 0.0f;
1502
1503 if(!off() && (md->openFlags() & 2 /*read*/))
1504 {
1505 const TrackLatencyInfo& li = md->getLatencyInfoMidi(true /*capture*/, false);
1506 const bool participate =
1507 (li._canCorrectOutputLatency ||
1508 li._canDominateOutputLatency ||
1509 MusEGlobal::config.correctUnterminatedInBranchLatency);
1510
1511 if(participate)
1512 {
1513 // Prepare the latency value to be passed to the compensator's writer,
1514 // by adjusting each route latency value. ie. the route with the worst-case
1515 // latency will get ZERO delay, while routes having smaller latency will get
1516 // MORE delay, to match all the signal timings together.
1517 // The route's audioLatencyOut should have already been calculated and
1518 // conveniently stored in the route.
1519 ir->audioLatencyOut = route_worst_latency - li._outputLatency;
1520 // Should not happen, but just in case.
1521 if((long int)ir->audioLatencyOut < 0)
1522 ir->audioLatencyOut = 0.0f;
1523 }
1524 }
1525 }
1526 }
1527 break;
1528
1529 case Route::TRACK_ROUTE:
1530 if(!ir->track)
1531 continue;
1532 if(ir->track->isMidiTrack())
1533 {
1534 // TODO
1535 }
1536 break;
1537
1538 default:
1539 break;
1540 }
1541 }
1542
1543 if(input)
1544 _latencyInfo._inputProcessed = true;
1545 else
1546 _latencyInfo._processed = true;
1547
1548 return _latencyInfo;
1549 }
1550
setLatencyCompWriteOffset(float worstCase)1551 void MidiTrack::setLatencyCompWriteOffset(float worstCase)
1552 {
1553 // If independent branches are NOT to affect project latency,
1554 // then there should be no need for any extra delay in the branch.
1555 if(!MusEGlobal::config.commonProjectLatency)
1556 {
1557 _latencyInfo._compensatorWriteOffset = 0;
1558 //fprintf(stderr, "MidiTrack::setLatencyCompWriteOffset() name:%s worstCase:%f _outputLatency:%f _compensatorWriteOffset:%lu\n",
1559 // name().toLatin1().constData(), worstCase, _latencyInfo._outputLatency, _latencyInfo._compensatorWriteOffset);
1560 return;
1561 }
1562
1563 if(_latencyInfo._canDominateOutputLatency)
1564 {
1565 const long unsigned int wc = worstCase;
1566 const long unsigned int ol = _latencyInfo._outputLatency;
1567 if(ol > wc)
1568 _latencyInfo._compensatorWriteOffset = 0;
1569 else
1570 _latencyInfo._compensatorWriteOffset = wc - ol;
1571 }
1572 else
1573 {
1574 // if(_latencyInfo._outputLatency < 0)
1575 _latencyInfo._compensatorWriteOffset = 0;
1576 // else
1577 // _latencyInfo._compensatorWriteOffset = _latencyInfo._outputLatency;
1578 }
1579
1580 //fprintf(stderr, "MidiTrack::setLatencyCompWriteOffset() name:%s worstCase:%f _outputLatency:%f _canDominateOutputLatency:%d _compensatorWriteOffset:%lu\n",
1581 // name().toLatin1().constData(), worstCase, _latencyInfo._outputLatency, _latencyInfo._canDominateOutputLatency, _latencyInfo._compensatorWriteOffset);
1582 }
1583
1584 //---------------------------------------------------------
1585 // noOutRoute
1586 //---------------------------------------------------------
1587
noOutRoute() const1588 bool MidiTrack::noOutRoute() const
1589 {
1590
1591 return _outRoutes.empty()
1592
1593 #ifdef _USE_MIDI_TRACK_SINGLE_OUT_PORT_CHAN_
1594 && (outChannel() < 0 || outPort() < 0 || !MusEGlobal::midiPorts[outPort()].device())
1595 #endif
1596 ;
1597 }
1598
1599 //---------------------------------------------------------
1600 // mappedPortChanCtrl
1601 //---------------------------------------------------------
1602
mappedPortChanCtrl(int * ctrl,int * port,MidiPort ** mport,int * channel) const1603 bool MidiTrack::mappedPortChanCtrl(int *ctrl, int *port, MidiPort** mport, int *channel) const
1604 {
1605 bool res = false;
1606 int t_ctrl = *ctrl;
1607 int t_port = outPort();
1608 int t_ch = outChannel();
1609 MidiPort* mp = &MusEGlobal::midiPorts[t_port];
1610
1611 const MidiController* mc = mp->drumController(t_ctrl);
1612 if(mc)
1613 {
1614 res = true;
1615 const int note = t_ctrl & 0x7f;
1616 // Is it a drum controller old_event, according to the track port's instrument?
1617 if(type() == Track::DRUM)
1618 {
1619 // Default to track port if -1 and track channel if -1.
1620 const int ch = drummap()[note].channel;
1621 if(ch != -1)
1622 t_ch = ch;
1623 const int p = drummap()[note].port;
1624 if(p != -1)
1625 t_port = p;
1626 t_ctrl &= ~0xff;
1627 t_ctrl |= drummap()[note].anote;
1628 }
1629 }
1630
1631 *ctrl = t_ctrl;
1632 if(port)
1633 (*port) = t_port;
1634 if(mport)
1635 (*mport) = &MusEGlobal::midiPorts[t_port];
1636 if(channel)
1637 (*channel) = t_ch;
1638
1639 return res;
1640 }
1641
1642 //---------------------------------------------------------
1643 // setOutChannel
1644 //---------------------------------------------------------
1645
setOutChannel(int i,bool doSignal)1646 MidiTrack::ChangedType_t MidiTrack::setOutChannel(int i, bool doSignal)
1647 {
1648 if(_outChannel == i)
1649 return NothingChanged;
1650 _outChannel = i;
1651 ChangedType_t res = ChannelChanged;
1652 if(updateDrummap(doSignal))
1653 res |= DrumMapChanged;
1654 return res;
1655 }
1656
1657 //---------------------------------------------------------
1658 // setOutPort
1659 //---------------------------------------------------------
1660
setOutPort(int i,bool doSignal)1661 MidiTrack::ChangedType_t MidiTrack::setOutPort(int i, bool doSignal)
1662 {
1663 if(_outPort == i)
1664 return NothingChanged;
1665 _outPort = i;
1666 ChangedType_t res = PortChanged;
1667 if(updateDrummap(doSignal))
1668 res |= DrumMapChanged;
1669 return res;
1670 }
1671
1672 //---------------------------------------------------------
1673 // setOutChanAndUpdate
1674 //---------------------------------------------------------
1675
setOutChanAndUpdate(int i,bool doSignal)1676 MidiTrack::ChangedType_t MidiTrack::setOutChanAndUpdate(int i, bool doSignal)
1677 {
1678 if(_outChannel == i)
1679 return NothingChanged;
1680
1681 removePortCtrlEvents(this);
1682 _outChannel = i;
1683 ChangedType_t res = ChannelChanged;
1684 if(updateDrummap(doSignal))
1685 res |= DrumMapChanged;
1686 addPortCtrlEvents(this);
1687 return res;
1688 }
1689
1690 //---------------------------------------------------------
1691 // setOutPortAndUpdate
1692 //---------------------------------------------------------
1693
setOutPortAndUpdate(int i,bool doSignal)1694 MidiTrack::ChangedType_t MidiTrack::setOutPortAndUpdate(int i, bool doSignal)
1695 {
1696 if(_outPort == i)
1697 return NothingChanged;
1698
1699 removePortCtrlEvents(this);
1700 _outPort = i;
1701 ChangedType_t res = PortChanged;
1702 if(updateDrummap(doSignal))
1703 res |= DrumMapChanged;
1704 addPortCtrlEvents(this);
1705 return res;
1706 }
1707
1708 //---------------------------------------------------------
1709 // setOutPortAndChannelAndUpdate
1710 //---------------------------------------------------------
1711
setOutPortAndChannelAndUpdate(int port,int ch,bool doSignal)1712 MidiTrack::ChangedType_t MidiTrack::setOutPortAndChannelAndUpdate(int port, int ch, bool doSignal)
1713 {
1714 if(_outPort == port && _outChannel == ch)
1715 return NothingChanged;
1716
1717 removePortCtrlEvents(this);
1718 _outPort = port;
1719 _outChannel = ch;
1720 ChangedType_t res = PortChanged | ChannelChanged;
1721 if(updateDrummap(doSignal))
1722 res |= DrumMapChanged;
1723 addPortCtrlEvents(this);
1724 return res;
1725 }
1726
1727 //---------------------------------------------------------
1728 // setInPortAndChannelMask
1729 // For old song files with port mask (max 32 ports) and channel mask (16 channels),
1730 // before midi routing was added (the iR button).
1731 //---------------------------------------------------------
1732
setInPortAndChannelMask(unsigned int portmask,int chanmask)1733 void MidiTrack::setInPortAndChannelMask(unsigned int portmask, int chanmask)
1734 {
1735 //bool changed = false;
1736 PendingOperationList operations;
1737
1738 for(int port = 0; port < 32; ++port) // 32 is the old maximum number of ports.
1739 {
1740 // If the port was not used in the song file to begin with, just ignore it.
1741 // This saves from having all of the first 32 ports' channels connected.
1742 if(!MusEGlobal::midiPorts[port].foundInSongFile())
1743 continue;
1744
1745 const int allch = (1 << MusECore::MUSE_MIDI_CHANNELS) - 1;
1746 // Check if Omni route will do...
1747 if(chanmask == allch)
1748 {
1749 // Route wanted?
1750 if(portmask & (1 << port))
1751 operations.add(MusECore::PendingOperationItem(MusECore::Route(port), MusECore::Route(this),
1752 MusECore::PendingOperationItem::AddRoute));
1753 else
1754 operations.add(MusECore::PendingOperationItem(MusECore::Route(port), MusECore::Route(this),
1755 MusECore::PendingOperationItem::DeleteRoute));
1756 }
1757 else
1758 // Add individual channels:
1759 for(int ch = 0; ch < MusECore::MUSE_MIDI_CHANNELS; ++ch)
1760 {
1761 // Route wanted?
1762 if(portmask & (1 << port) && (chanmask & (1 << ch)))
1763 operations.add(MusECore::PendingOperationItem(MusECore::Route(port, ch), MusECore::Route(this, ch),
1764 MusECore::PendingOperationItem::AddRoute));
1765 else
1766 operations.add(MusECore::PendingOperationItem(MusECore::Route(port, ch), MusECore::Route(this, ch),
1767 MusECore::PendingOperationItem::DeleteRoute));
1768 }
1769 }
1770
1771 // if(changed)
1772 // {
1773 // MusEGlobal::audio->msgUpdateSoloStates();
1774 // MusEGlobal::song->update(SC_ROUTE);
1775 // }
1776
1777 if(!operations.empty())
1778 {
1779 MusEGlobal::audio->msgExecutePendingOperations(operations, true);
1780 // MusEGlobal::song->update(SC_ROUTE);
1781 }
1782 }
1783
1784
1785 //---------------------------------------------------------
1786 // newPart
1787 //---------------------------------------------------------
1788
newPart(Part * p,bool clone)1789 Part* MidiTrack::newPart(Part*p, bool clone)
1790 {
1791 MidiPart* part;
1792 if(!p)
1793 {
1794 part = new MidiPart(this);
1795 }
1796 else
1797 {
1798 if (clone)
1799 {
1800 part = (MidiPart*)p->createNewClone();
1801 part->setTrack(this);
1802 }
1803 else
1804 {
1805 part = (MidiPart*)p->duplicate();
1806 part->setTrack(this);
1807 }
1808 }
1809 return part;
1810 }
1811
1812 //---------------------------------------------------------
1813 // addStuckNote
1814 //---------------------------------------------------------
1815
addStuckNote(const MidiPlayEvent & ev)1816 bool MidiTrack::addStuckNote(const MidiPlayEvent& ev)
1817 {
1818 stuckNotes.add(ev);
1819 return true;
1820 }
1821
1822 //---------------------------------------------------------
1823 // addStuckLiveNote
1824 // Return true if note was added.
1825 //---------------------------------------------------------
1826
addStuckLiveNote(int port,int chan,int note,int vel)1827 bool MidiTrack::addStuckLiveNote(int port, int chan, int note, int vel)
1828 {
1829 // for(ciMPEvent k = stuckLiveNotes.begin(); k != stuckLiveNotes.end(); ++k)
1830 // {
1831 // // We're looking for port, channel, and note. Time and velocity are not relevant.
1832 // if((*k).port() == port &&
1833 // (*k).channel() == chan &&
1834 // (*k).dataA() == note)
1835 // return false;
1836 // }
1837 stuckLiveNotes.add(MidiPlayEvent(0, port, chan, ME_NOTEOFF, note, vel)); // Mark for immediate playback
1838 return true;
1839 }
1840
1841 //---------------------------------------------------------
1842 // removeStuckLiveNote
1843 // Return true if note was removed.
1844 //---------------------------------------------------------
1845
removeStuckLiveNote(int port,int chan,int note)1846 bool MidiTrack::removeStuckLiveNote(int port, int chan, int note)
1847 {
1848 for(ciMPEvent k = stuckLiveNotes.begin(); k != stuckLiveNotes.end(); ++k)
1849 {
1850 // We're looking for port, channel, and note. Time and velocity are not relevant.
1851 if((*k).port() == port &&
1852 (*k).channel() == chan &&
1853 (*k).dataA() == note)
1854 {
1855 stuckLiveNotes.erase(k);
1856 return true;
1857 }
1858 }
1859 return false;
1860 }
1861
1862 //---------------------------------------------------------
1863 // stuckLiveNoteExists
1864 // Return true if note exists.
1865 //---------------------------------------------------------
1866
stuckLiveNoteExists(int port,int chan,int note)1867 bool MidiTrack::stuckLiveNoteExists(int port, int chan, int note)
1868 {
1869 for(ciMPEvent k = stuckLiveNotes.begin(); k != stuckLiveNotes.end(); ++k)
1870 {
1871 // We're looking for port, channel, and note. Time and velocity are not relevant.
1872 if((*k).port() == port &&
1873 (*k).channel() == chan &&
1874 (*k).dataA() == note)
1875 return true;
1876 }
1877 return false;
1878 }
1879
1880 //---------------------------------------------------------
1881 // automationType
1882 //---------------------------------------------------------
1883
automationType() const1884 AutomationType MidiTrack::automationType() const
1885 {
1886 MidiPort* port = &MusEGlobal::midiPorts[outPort()];
1887 return port->automationType(outChannel());
1888 }
1889
1890 //---------------------------------------------------------
1891 // setAutomationType
1892 //---------------------------------------------------------
1893
setAutomationType(AutomationType t)1894 void MidiTrack::setAutomationType(AutomationType t)
1895 {
1896 MidiPort* port = &MusEGlobal::midiPorts[outPort()];
1897 port->setAutomationType(outChannel(), t);
1898 }
1899
1900 //---------------------------------------------------------
1901 // MidiTrack::write
1902 //---------------------------------------------------------
1903
write(int level,Xml & xml) const1904 void MidiTrack::write(int level, Xml& xml) const
1905 {
1906 const char* tag;
1907
1908 if (type() == MIDI)
1909 tag = "miditrack";
1910 else if (type() == DRUM)
1911 tag = "newdrumtrack";
1912 else {
1913 printf("THIS SHOULD NEVER HAPPEN: non-midi-type in MidiTrack::write()\n");
1914 tag="";
1915 }
1916
1917 xml.tag(level++, tag);
1918 Track::writeProperties(level, xml);
1919
1920 xml.intTag(level, "device", outPort());
1921 xml.intTag(level, "channel", outChannel());
1922 xml.intTag(level, "locked", _locked);
1923
1924 xml.intTag(level, "transposition", transposition);
1925 xml.intTag(level, "velocity", velocity);
1926 xml.intTag(level, "delay", delay);
1927 xml.intTag(level, "len", len);
1928 xml.intTag(level, "compression", compression);
1929 xml.intTag(level, "automation", int(automationType()));
1930 xml.intTag(level, "clef", int(clefType));
1931
1932 const PartList* pl = cparts();
1933 for (ciPart p = pl->begin(); p != pl->end(); ++p)
1934 p->second->write(level, xml);
1935
1936 writeOurDrumSettings(level, xml);
1937
1938 xml.etag(level, tag);
1939 }
1940
writeOurDrumSettings(int level,Xml & xml) const1941 void MidiTrack::writeOurDrumSettings(int level, Xml& xml) const
1942 {
1943 xml.tag(level++, "our_drum_settings");
1944 _workingDrumMapPatchList->write(level, xml);
1945 xml.intTag(level, "ordering_tied", _drummap_ordering_tied_to_patch);
1946 xml.etag(level, "our_drum_settings");
1947 }
1948
dumpMap()1949 void MidiTrack::dumpMap()
1950 {
1951 if(type() != DRUM)
1952 return;
1953 const int port = outPort();
1954 if(port < 0 || port >= MusECore::MIDI_PORTS)
1955 return;
1956 MidiPort* mp = &MusEGlobal::midiPorts[port];
1957 const int chan = outChannel();
1958 const int patch = mp->hwCtrlState(chan, MusECore::CTRL_PROGRAM);
1959
1960 fprintf(stderr, "Drum map for patch:%d\n\n", patch);
1961
1962 fprintf(stderr, "name\t\tvol\tqnt\tlen\tchn\tprt\tlv1\tlv2\tlv3\tlv4\tenote\t\tanote\\ttmute\thide\n");
1963
1964 DrumMap all_dm,
1965 #ifdef _USE_INSTRUMENT_OVERRIDES_
1966 instr_dm, instrdef_dm,
1967 #endif
1968 track_dm, trackdef_dm;
1969
1970 for(int index = 0; index < 128; ++index)
1971 {
1972 getMapItem(patch, index, all_dm, WorkingDrumMapEntry::AllOverrides);
1973 getMapItem(patch, index, track_dm, WorkingDrumMapEntry::TrackOverride);
1974 getMapItem(patch, index, trackdef_dm, WorkingDrumMapEntry::TrackDefaultOverride);
1975 #ifdef _USE_INSTRUMENT_OVERRIDES_
1976 getMapItem(patch, index, instr_dm, WorkingDrumMapEntry::InstrumentOverride);
1977 getMapItem(patch, index, instrdef_dm, WorkingDrumMapEntry::InstrumentDefaultOverride);
1978 #endif
1979
1980 fprintf(stderr, "Index:%d ", index);
1981 fprintf(stderr, "All overrides:\n");
1982 all_dm.dump();
1983
1984 #ifdef _USE_INSTRUMENT_OVERRIDES_
1985 fprintf(stderr, "Instrument override:\n");
1986 instr_dm.dump();
1987 fprintf(stderr, "Instrument default override:\n");
1988 instrdef_dm.dump();
1989 #endif
1990
1991 fprintf(stderr, "Track override:\n");
1992 track_dm.dump();
1993 fprintf(stderr, "Track default override:\n");
1994 trackdef_dm.dump();
1995
1996 fprintf(stderr, "\n");
1997 }
1998 }
1999
2000
2001 //---------------------------------------------------------
2002 // MidiTrack::read
2003 //---------------------------------------------------------
2004
read(Xml & xml)2005 void MidiTrack::read(Xml& xml)
2006 {
2007 unsigned int portmask = 0;
2008 int chanmask = 0;
2009 bool portmask_found = false;
2010 bool chanmask_found = false;
2011
2012 for (;;) {
2013 Xml::Token token = xml.parse();
2014 const QString& tag = xml.s1();
2015 switch (token) {
2016 case Xml::Error:
2017 case Xml::End:
2018 goto out_of_MidiTrackRead_forloop;
2019 case Xml::TagStart:
2020 if (tag == "transposition")
2021 transposition = xml.parseInt();
2022 else if (tag == "velocity")
2023 velocity = xml.parseInt();
2024 else if (tag == "delay")
2025 delay = xml.parseInt();
2026 else if (tag == "len")
2027 len = xml.parseInt();
2028 else if (tag == "compression")
2029 compression = xml.parseInt();
2030 else if (tag == "part") {
2031 Part* p = Part::readFromXml(xml, this);
2032 if(p)
2033 parts()->add(p);
2034 }
2035 // TODO: These two device and channel sections will need to change
2036 // if and when multiple output routes are supported.
2037 // For now just look for the first default (there's only one)...
2038 else if (tag == "device") {
2039 int port = xml.parseInt();
2040 if(port == -1)
2041 {
2042 for(int i = 0; i < MusECore::MIDI_PORTS; ++i)
2043 {
2044 if(MusEGlobal::midiPorts[i].defaultOutChannels())
2045 {
2046 port = i;
2047 break;
2048 }
2049 }
2050 }
2051 if(port == -1)
2052 port = 0;
2053 setOutPort(port);
2054 }
2055 else if (tag == "channel") {
2056 int chan = xml.parseInt();
2057 if(chan == -1)
2058 {
2059 for(int i = 0; i < MusECore::MIDI_PORTS; ++i)
2060 {
2061 int defchans = MusEGlobal::midiPorts[i].defaultOutChannels();
2062 for(int c = 0; c < MusECore::MUSE_MIDI_CHANNELS; ++c)
2063 {
2064 if(defchans & (1 << c))
2065 {
2066 chan = c;
2067 break;
2068 }
2069 }
2070 if(chan != -1)
2071 break;
2072 }
2073 }
2074 if(chan == -1)
2075 chan = 0;
2076 setOutChannel(chan);
2077 }
2078 else if (tag == "inportMap")
2079 {
2080 portmask = xml.parseUInt(); // Obsolete but support old files.
2081 portmask_found = true;
2082 }
2083 else if (tag == "inchannelMap")
2084 {
2085 chanmask = xml.parseInt(); // Obsolete but support old files.
2086 chanmask_found = true;
2087 }
2088 else if (tag == "locked")
2089 _locked = xml.parseInt();
2090 else if (tag == "echo") // Obsolete but support old files.
2091 setRecMonitor(xml.parseInt());
2092 else if (tag == "automation")
2093 setAutomationType(AutomationType(xml.parseInt()));
2094 else if (tag == "clef")
2095 clefType = (clefTypes)xml.parseInt();
2096 else if (tag == "our_drum_settings")
2097 readOurDrumSettings(xml);
2098 else if (Track::readProperties(xml, tag)) {
2099 // version 1.0 compatibility:
2100 if (tag == "track" && xml.majorVersion() == 1 && xml.minorVersion() == 0)
2101 break;
2102 xml.unknown("MidiTrack");
2103 }
2104 break;
2105 case Xml::Attribut:
2106 break;
2107 case Xml::TagEnd:
2108 if (tag == "miditrack" || tag == "drumtrack" || tag == "newdrumtrack")
2109 {
2110 if(portmask_found && chanmask_found)
2111 setInPortAndChannelMask(portmask, chanmask); // Support old files.
2112 goto out_of_MidiTrackRead_forloop;
2113 }
2114 default:
2115 break;
2116 }
2117 }
2118
2119 out_of_MidiTrackRead_forloop:
2120 chainTrackParts(this);
2121 }
2122
readOurDrumSettings(Xml & xml)2123 void MidiTrack::readOurDrumSettings(Xml& xml)
2124 {
2125 bool doUpdateDrummap = false;
2126 for (;;)
2127 {
2128 Xml::Token token = xml.parse();
2129 if (token == Xml::Error || token == Xml::End)
2130 break;
2131 const QString& tag = xml.s1();
2132 switch (token)
2133 {
2134 case Xml::TagStart:
2135 if (tag == "tied")
2136 xml.parseInt(); // Obsolete.
2137 else if (tag == "ordering_tied")
2138 _drummap_ordering_tied_to_patch = xml.parseInt();
2139
2140 else if (tag == "our_drummap" || // OBSOLETE. Support old files.
2141 tag == "drummap" || // OBSOLETE. Support old files.
2142 tag == "drumMapPatch")
2143 {
2144 // false = Do not fill in unused items.
2145 _workingDrumMapPatchList->read(xml, false);
2146 doUpdateDrummap = true;
2147 }
2148
2149 else
2150 xml.unknown("our_drum_settings");
2151 break;
2152
2153 case Xml::TagEnd:
2154 if (tag == "our_drum_settings")
2155 {
2156 if(doUpdateDrummap)
2157 {
2158 // We must ensure that there are NO duplicate enote fields,
2159 // since the instrument map may have changed by now.
2160 //normalizeWorkingDrumMapPatchList();
2161
2162 updateDrummap(false);
2163 }
2164 return;
2165 }
2166
2167 default:
2168 break;
2169 }
2170 }
2171 }
2172
2173 //---------------------------------------------------------
2174 // addPart
2175 //---------------------------------------------------------
2176
addPart(Part * p)2177 iPart Track::addPart(Part* p)
2178 {
2179 p->setTrack(this);
2180 return _parts.add(p);
2181 }
2182
2183 //---------------------------------------------------------
2184 // findPart
2185 //---------------------------------------------------------
2186
findPart(unsigned tick)2187 Part* Track::findPart(unsigned tick)
2188 {
2189 for (iPart i = _parts.begin(); i != _parts.end(); ++i) {
2190 Part* part = i->second;
2191 if (tick >= part->tick() && tick < (part->tick()+part->lenTick()))
2192 return part;
2193 }
2194 return 0;
2195 }
2196
selectEvents(bool select,unsigned long t0,unsigned long t1)2197 bool Track::selectEvents(bool select, unsigned long t0, unsigned long t1)
2198 {
2199 bool ret = false;
2200 PartList* pl = parts();
2201 for(iPart ip = pl->begin(); ip != pl->end(); ++ip)
2202 {
2203 if(ip->second->selectEvents(select, t0, t1))
2204 ret = true;
2205 }
2206 return ret;
2207 }
2208
2209 //---------------------------------------------------------
2210 // Track::writeProperties
2211 //---------------------------------------------------------
2212
writeProperties(int level,Xml & xml) const2213 void Track::writeProperties(int level, Xml& xml) const
2214 {
2215 xml.strTag(level, "name", _name);
2216 if (!_comment.isEmpty())
2217 xml.strTag(level, "comment", _comment);
2218 xml.intTag(level, "record", _recordFlag);
2219 xml.intTag(level, "mute", mute());
2220 xml.intTag(level, "solo", solo());
2221 xml.intTag(level, "off", off());
2222 xml.intTag(level, "channels", _channels);
2223 xml.intTag(level, "height", _height);
2224 xml.intTag(level, "locked", _locked);
2225 xml.intTag(level, "recMonitor", _recMonitor);
2226 if (_selected)
2227 {
2228 xml.intTag(level, "selected", _selected);
2229 xml.intTag(level, "selectionOrder", _selectionOrder);
2230 }
2231 if (m_color.isValid())
2232 xml.strTag(level, "color", m_color.name());
2233 }
2234
2235 //---------------------------------------------------------
2236 // Track::readProperties
2237 //---------------------------------------------------------
2238
readProperties(Xml & xml,const QString & tag)2239 bool Track::readProperties(Xml& xml, const QString& tag)
2240 {
2241 if (tag == "name")
2242 _name = xml.parse1();
2243 else if (tag == "comment")
2244 _comment = xml.parse1();
2245 else if (tag == "record") {
2246 bool recordFlag = xml.parseInt();
2247 if (type() == TrackType::AUDIO_OUTPUT)
2248 recordFlag = false;
2249 setRecordFlag1(recordFlag);
2250 setRecordFlag2(recordFlag);
2251 }
2252 else if (tag == "mute")
2253 _mute = xml.parseInt();
2254 else if (tag == "solo")
2255 _solo = xml.parseInt();
2256 else if (tag == "off")
2257 _off = xml.parseInt();
2258 else if (tag == "height")
2259 _height = xml.parseInt();
2260 else if (tag == "channels")
2261 {
2262 setChannels(xml.parseInt());
2263 }
2264 else if (tag == "locked")
2265 _locked = xml.parseInt();
2266 else if (tag == "recMonitor")
2267 setRecMonitor(xml.parseInt());
2268 else if (tag == "selected")
2269 _selected = xml.parseInt();
2270 else if (tag == "selectionOrder")
2271 _selectionOrder = xml.parseInt();
2272 else if (tag == "color") {
2273 QString c = xml.parse1();
2274 if (QColor::isValidColor(c))
2275 m_color.setNamedColor(c);
2276 }
2277 else
2278 return true;
2279 return false;
2280 }
2281
2282 //---------------------------------------------------------
2283 // writeRouting
2284 //---------------------------------------------------------
2285
writeRouting(int level,Xml & xml) const2286 void Track::writeRouting(int level, Xml& xml) const
2287 {
2288 QString s;
2289 if (type() == Track::AUDIO_INPUT)
2290 {
2291 const RouteList* rl = &_inRoutes;
2292 for (ciRoute r = rl->begin(); r != rl->end(); ++r)
2293 {
2294 if((r->type == Route::TRACK_ROUTE && r->track) || (r->type != Route::TRACK_ROUTE && !r->name().isEmpty()))
2295 {
2296 s = "Route";
2297 if(r->channel != -1)
2298 s += QString(" channel=\"%1\"").arg(r->channel);
2299
2300 xml.tag(level++, s.toLatin1().constData());
2301
2302 // New routing scheme.
2303 s = "source";
2304 if(r->type == Route::TRACK_ROUTE)
2305 s += QString(" track=\"%1\"/").arg(MusEGlobal::song->tracks()->index(r->track));
2306 else
2307 s += QString(" type=\"%1\" name=\"%2\"/").arg(r->type).arg(Xml::xmlString(r->name()));
2308 xml.tag(level, s.toLatin1().constData());
2309
2310 xml.tag(level, "dest track=\"%d\"/", MusEGlobal::song->tracks()->index(this));
2311
2312 xml.etag(level--, "Route");
2313 }
2314 }
2315 }
2316
2317 const RouteList* rl = &_outRoutes;
2318 for (ciRoute r = rl->begin(); r != rl->end(); ++r)
2319 {
2320 // Ignore Audio Output to Audio Input routes.
2321 // They are taken care of by Audio Input in the section above.
2322 if((r->type == Route::TRACK_ROUTE && r->track && r->track->type() != Track::AUDIO_INPUT) ||
2323 (r->type != Route::TRACK_ROUTE && (!r->name().isEmpty() || r->midiPort != -1)))
2324 {
2325 s = "Route";
2326 if(r->channel != -1)
2327 s += QString(" channel=\"%1\"").arg(r->channel);
2328 if(r->channels != -1)
2329 s += QString(" channels=\"%1\"").arg(r->channels);
2330 if(r->remoteChannel != -1)
2331 s += QString(" remch=\"%1\"").arg(r->remoteChannel);
2332
2333 xml.tag(level++, s.toLatin1().constData());
2334
2335 // Allow for a regular mono or stereo track to feed a multi-channel synti.
2336 xml.tag(level, "source track=\"%d\"/", MusEGlobal::song->tracks()->index(this));
2337
2338 s = "dest";
2339
2340 if(r->type != Route::TRACK_ROUTE && r->type != Route::MIDI_PORT_ROUTE)
2341 s += QString(" type=\"%1\"").arg(r->type);
2342
2343 if(r->type == Route::MIDI_PORT_ROUTE)
2344 s += QString(" mport=\"%1\"/").arg(r->midiPort);
2345 else if(r->type == Route::TRACK_ROUTE)
2346 s += QString(" track=\"%1\"/").arg(MusEGlobal::song->tracks()->index(r->track));
2347 else
2348 s += QString(" name=\"%1\"/").arg(Xml::xmlString(r->name()));
2349
2350 xml.tag(level, s.toLatin1().constData());
2351
2352 xml.etag(level--, "Route");
2353 }
2354 }
2355 }
2356
getFirstControllerValue(int ctrl,int def)2357 int MidiTrack::getFirstControllerValue(int ctrl, int def)
2358 {
2359 int val=def;
2360 unsigned tick=-1; // maximum integer
2361
2362 for (iPart pit=parts()->begin(); pit!=parts()->end(); pit++)
2363 {
2364 Part* part=pit->second;
2365 if (part->tick() > tick) break; // ignore this and the rest. we won't find anything new.
2366 for (ciEvent eit=part->events().begin(); eit!=part->events().end(); eit++)
2367 {
2368 if (eit->first+part->tick() >= tick) break;
2369 if (eit->first > part->lenTick()) break; // ignore events past the end of the part
2370 // else if (eit->first+part->tick() < tick) and
2371 if (eit->second.type()==Controller && eit->second.dataA()==ctrl)
2372 {
2373 val = eit->second.dataB();
2374 tick = eit->first+part->tick();
2375 break;
2376 }
2377 }
2378 }
2379
2380 return val;
2381 }
2382
getControllerChangeAtTick(unsigned tick,int ctrl,int def)2383 int MidiTrack::getControllerChangeAtTick(unsigned tick, int ctrl, int def)
2384 {
2385 for (iPart pit=parts()->begin(); pit!=parts()->end(); pit++)
2386 {
2387 Part* part=pit->second;
2388 if (part->tick() > tick) break; // ignore this and the rest. we'd find nothing any more
2389 if (part->endTick() < tick) continue; // ignore only this.
2390 for (ciEvent eit=part->events().begin(); eit!=part->events().end(); eit++)
2391 {
2392 if (eit->first+part->tick() > tick) break; // we won't find anything in this part from now on.
2393 if (eit->first > part->lenTick()) break; // ignore events past the end of the part
2394 if (eit->first+part->tick() < tick) continue; // ignore only this
2395
2396 // else if (eit->first+part->tick() == tick) and
2397 if (eit->second.type()==Controller && eit->second.dataA()==ctrl)
2398 return eit->second.dataB();
2399 }
2400 }
2401
2402 return def;
2403 }
2404
2405 // returns the tick where this CC gets overridden by a new one
2406 // returns UINT_MAX for "never"
getControllerValueLifetime(unsigned tick,int ctrl)2407 unsigned MidiTrack::getControllerValueLifetime(unsigned tick, int ctrl)
2408 {
2409 unsigned result=UINT_MAX;
2410
2411 for (iPart pit=parts()->begin(); pit!=parts()->end(); pit++)
2412 {
2413 Part* part=pit->second;
2414 if (part->tick() > result) break; // ignore this and the rest. we won't find anything new.
2415 if (part->endTick() < tick) continue; // ignore only this part, we won't find anything there.
2416 for (ciEvent eit=part->events().begin(); eit!=part->events().end(); eit++)
2417 {
2418 if (eit->first+part->tick() >= result) break;
2419 if (eit->first > part->lenTick()) break; // ignore events past the end of the part
2420 // else if (eit->first+part->tick() < result) and
2421 if (eit->first+part->tick() > tick &&
2422 eit->second.type()==Controller && eit->second.dataA()==ctrl)
2423 {
2424 result = eit->first+part->tick();
2425 break;
2426 }
2427 }
2428 }
2429
2430 return result;
2431 }
2432
2433 //---------------------------------------------------------
2434 // updateDrummap
2435 // If audio is running (and not idle) this should only be called by the rt audio thread.
2436 // Returns true if map was changed.
2437 //---------------------------------------------------------
2438
updateDrummap(int doSignal)2439 bool MidiTrack::updateDrummap(int doSignal)
2440 {
2441 if(type() != Track::DRUM || _outPort < 0 || _outPort >= MusECore::MIDI_PORTS)
2442 return false;
2443 MidiPort* mp = &MusEGlobal::midiPorts[_outPort];
2444 const int patch = mp->hwCtrlState(_outChannel, CTRL_PROGRAM);
2445 bool map_changed;
2446 DrumMap ndm;
2447
2448 map_changed = false;
2449 for(int i = 0; i < 128; i++)
2450 {
2451 getMapItem(patch, i, ndm, WorkingDrumMapEntry::AllOverrides);
2452 DrumMap& tdm = _drummap[i];
2453 if(ndm != tdm)
2454 {
2455 tdm = ndm;
2456 map_changed = true;
2457 }
2458 // Be sure to update the drum input note map. Probably wise (and easy) to do it always.
2459 drum_in_map[(int)tdm.enote] = i;
2460 }
2461
2462 // Ensure there are NO duplicate enote fields. Returns true if somethng was changed.
2463 if(normalizeDrumMap(patch))
2464 map_changed = true;
2465
2466 if(map_changed)
2467 {
2468 // Update the drum in (enote) map.
2469 update_drum_in_map();
2470
2471 // TODO Move this to gui thread where it's safe to do so - this is only gui stuff.
2472 if(drummap_ordering_tied_to_patch())
2473 // TODO This is not exactly rt friendly since it may de/allocate.
2474 init_drum_ordering();
2475 }
2476
2477 // TODO Do this outside since we may be called as part of multiple tracks operations.
2478 if(map_changed && doSignal)
2479 {
2480 // It is possible we are being called from gui thread already, in audio idle mode.
2481 // Will this still work, and not conflict with audio sending the same message?
2482 // Are we are not supposed to write to an fd from different threads?
2483 if(!MusEGlobal::audio || MusEGlobal::audio->isIdle())
2484 // Directly emit SC_DRUMMAP song changed signal.
2485 MusEGlobal::song->update(SC_DRUMMAP);
2486 else
2487 // Tell the gui to emit SC_DRUMMAP song changed signal.
2488 MusEGlobal::audio->sendMsgToGui('D'); // Drum map changed.
2489
2490 return true;
2491 }
2492
2493 return map_changed;
2494 }
2495
set_drummap_ordering_tied_to_patch(bool val)2496 void MidiTrack::set_drummap_ordering_tied_to_patch(bool val)
2497 {
2498 _drummap_ordering_tied_to_patch=val;
2499 if (val) init_drum_ordering();
2500 }
2501
modifyWorkingDrumMap(WorkingDrumMapList & list,bool isReset,bool includeDefault,bool isInstrumentMod,bool doWholeMap)2502 void MidiTrack::modifyWorkingDrumMap(WorkingDrumMapList& list, bool isReset, bool includeDefault, bool
2503 #ifdef _USE_INSTRUMENT_OVERRIDES_
2504 isInstrumentMod
2505 #endif
2506 , bool doWholeMap)
2507 {
2508 //if(!isDrumTrack())
2509 if(type() != DRUM)
2510 return;
2511 const int port = outPort();
2512 if(port < 0 || port >= MusECore::MIDI_PORTS)
2513 return;
2514 MidiPort* mp = &MusEGlobal::midiPorts[port];
2515 const int chan = outChannel();
2516 const int patch = mp->hwCtrlState(chan, MusECore::CTRL_PROGRAM);
2517
2518 int index;
2519 int idx_end;
2520 int other_index;
2521 int fields;
2522 int cur_enote;
2523 int new_enote;
2524 // DrumMap orig_dm;
2525 DrumMap other_dm;
2526 WorkingDrumMapEntry other_wdme;
2527 #ifdef _USE_INSTRUMENT_OVERRIDES_
2528 MidiInstrument* instr = mp->instrument();
2529 #endif
2530 for(iWorkingDrumMapPatch_t iwdp = list.begin(); iwdp != list.end(); ++iwdp)
2531 {
2532 index = doWholeMap ? 0 : iwdp->first;
2533 idx_end = doWholeMap ? 128 : index + 1;
2534 for( ; index < idx_end; ++index)
2535 {
2536 DrumMap& dm = _drummap[index];
2537 WorkingDrumMapEntry& wdme = iwdp->second;
2538
2539 fields = wdme._fields;
2540
2541 #ifdef _USE_INSTRUMENT_OVERRIDES_
2542 if(isInstrumentMod)
2543 {
2544 if(instr)
2545 instr->setWorkingDrumMapItem(patch, index, wdme, isReset);
2546 }
2547 else
2548 #endif
2549
2550 // FIXME Possible non realtime-friendly allocation. There will be adding new list and copying of 'name' QString here.
2551 if(isReset)
2552 {
2553 // cur_enote = dm.enote;
2554 _workingDrumMapPatchList->remove(patch, index, wdme._fields, includeDefault);
2555 getMapItem(patch, index, dm, WorkingDrumMapEntry::AllOverrides);
2556 // REMOVE Tim. newdrums. Removed.
2557 // new_enote = dm.enote;
2558 // other_index = drum_in_map[new_enote];
2559 //
2560 // if(fields & WorkingDrumMapEntry::ENoteField && other_index != index)
2561 // {
2562 // // In doWholeMap mode, a previous index iteration may have already cleared the other ENote field.
2563 // // So do this only if there is a track override on the ENote field.
2564 // if(//doWholeMap &&
2565 // (isWorkingMapItem(other_index, WorkingDrumMapEntry::ENoteField, patch) &
2566 // (WorkingDrumMapEntry::TrackOverride | WorkingDrumMapEntry::TrackDefaultOverride)))
2567 // {
2568 // // Here we need to see the original map item value /before/ any overrides, so that we can
2569 // // tell whether this other_index brute-force 'reset' value is still technically an
2570 // // override, and either remove or add (modify) the list appropriately.
2571 // getMapItem(patch, other_index, other_dm, WorkingDrumMapEntry::NoOverride);
2572 // if(other_dm.enote == cur_enote)
2573 // {
2574 // // The values are equal. This is technically no longer a track override and we may remove it.
2575 // _workingDrumMapPatchList->remove(patch, other_index, WorkingDrumMapEntry::ENoteField, includeDefault);
2576 // }
2577 // else
2578 // {
2579 // // The values are not equal. This is technically still a track override, so add (modify) it.
2580 // other_dm.enote = cur_enote;
2581 // WorkingDrumMapEntry other_wdme(other_dm, WorkingDrumMapEntry::ENoteField);
2582 // _workingDrumMapPatchList->add(patch, other_index, other_wdme);
2583 // }
2584 //
2585 // _drummap[other_index].enote = cur_enote;
2586 // drum_in_map[cur_enote] = other_index;
2587 // }
2588 // drum_in_map[new_enote] = index;
2589 // }
2590 }
2591 else
2592 {
2593 cur_enote = dm.enote;
2594 if(includeDefault)
2595 {
2596 // We are 'promoting' the fields to default patch list...
2597 other_wdme._fields = fields;
2598 other_wdme._mapItem = dm;
2599 // Add the item to the default patch drum list.
2600 _workingDrumMapPatchList->add(CTRL_PROGRAM_VAL_DONT_CARE, index, other_wdme);
2601 // Now remove the item from the non-default patch drum list.
2602 if(patch != CTRL_PROGRAM_VAL_DONT_CARE)
2603 _workingDrumMapPatchList->remove(patch, index, WorkingDrumMapEntry::AllFields, false); // Do not include defaults.
2604 }
2605 else
2606 {
2607 if(doWholeMap)
2608 {
2609 if(fields == WorkingDrumMapEntry::AllFields)
2610 {
2611 other_wdme._fields = fields;
2612 other_wdme._mapItem = dm;
2613 _workingDrumMapPatchList->add(patch, index, other_wdme);
2614 }
2615 else
2616 _workingDrumMapPatchList->add(patch, index, wdme);
2617 }
2618 else
2619 {
2620 _workingDrumMapPatchList->add(patch, index, wdme);
2621 getMapItem(patch, index, dm, WorkingDrumMapEntry::AllOverrides);
2622 }
2623 }
2624
2625 if(!doWholeMap && (fields & WorkingDrumMapEntry::ENoteField))
2626 {
2627 new_enote = dm.enote;
2628 other_index = drum_in_map[new_enote];
2629 // If there is already another track override on the other index we must change it.
2630 if(isWorkingMapItem(other_index, WorkingDrumMapEntry::ENoteField, patch) != WorkingDrumMapEntry::NoOverride)
2631 {
2632 other_dm.enote = cur_enote;
2633 //WorkingDrumMapEntry other_wdme(other_dm, WorkingDrumMapEntry::ENoteField);
2634 other_wdme._mapItem = other_dm;
2635 other_wdme._fields = WorkingDrumMapEntry::ENoteField;
2636 if(includeDefault)
2637 {
2638 _workingDrumMapPatchList->add(CTRL_PROGRAM_VAL_DONT_CARE, other_index, other_wdme);
2639 // Now remove the item from the non-default patch drum list.
2640 if(patch != CTRL_PROGRAM_VAL_DONT_CARE)
2641 _workingDrumMapPatchList->remove(patch, other_index, WorkingDrumMapEntry::ENoteField, false); // Do not include defaults.
2642 }
2643 else
2644 _workingDrumMapPatchList->add(patch, other_index, other_wdme);
2645
2646 //_drummap[other_index].enote = cur_enote;
2647 //drum_in_map[cur_enote] = other_index;
2648 //drum_in_map[new_enote] = index;
2649 }
2650 }
2651 }
2652 }
2653 }
2654
2655 // Ensure there are NO duplicate enote fields.
2656 //if(normalizeDrumMap(patch))
2657 // If anything changed, update the drum in map.
2658 // update_drum_in_map();
2659 updateDrummap(false); // No signal.
2660 }
2661
setWorkingDrumMap(WorkingDrumMapPatchList * list,bool isInstrumentMod)2662 void MidiTrack::setWorkingDrumMap(WorkingDrumMapPatchList* list, bool
2663 #ifdef _USE_INSTRUMENT_OVERRIDES_
2664 isInstrumentMod
2665 #endif
2666 )
2667 {
2668 //if(!isDrumTrack())
2669 if(type() != DRUM)
2670 return;
2671
2672 #ifdef _USE_INSTRUMENT_OVERRIDES_
2673 if(isInstrumentMod)
2674 {
2675 // TODO
2676 // const int port = outPort();
2677 // if(port < 0 || port >= MIDI_PORTS)
2678 // return;
2679 // MidiPort* mp = &MusEGlobal::midiPorts[port];
2680 // MidiInstrument* instr = mp->instrument();
2681 // instr->setWorkingDrumMap();
2682 return;
2683 }
2684 #endif
2685
2686 _workingDrumMapPatchList = list;
2687
2688 // We must ensure that there are NO duplicate enote fields,
2689 // since the instrument map may have changed by now.
2690 //normalizeWorkingDrumMapPatchList();
2691
2692 updateDrummap(false); // No signal.
2693 update_drum_in_map();
2694 }
2695
getMapItemAt(int tick,int index,DrumMap & dest_map,int overrideType) const2696 void MidiTrack::getMapItemAt(int tick, int index, DrumMap& dest_map, int overrideType) const
2697 {
2698 //if(!isDrumTrack())
2699 if(type() != DRUM)
2700 {
2701 dest_map = iNewDrumMap[index];
2702 return;
2703 }
2704 const int port = outPort();
2705 if(port < 0 || port >= MusECore::MIDI_PORTS)
2706 {
2707 dest_map = iNewDrumMap[index];
2708 return;
2709 }
2710 const MidiPort* mp = &MusEGlobal::midiPorts[port];
2711 const int track_chan = outChannel();
2712
2713 // Get the patch number at tick, contributed by any part,
2714 // ignoring values outside of their parts. We must include
2715 // muted or off parts or tracks in the search since this is an
2716 // operation that must not be affected by mute or off.
2717 const int track_patch = mp->getVisibleCtrl(track_chan, tick, MusECore::CTRL_PROGRAM, true, true, true);
2718
2719 // Get the instrument's map item, and include any requested overrides.
2720 getMapItem(track_patch, index, dest_map, overrideType);
2721 }
2722
getMapItem(int patch,int index,DrumMap & dest_map,int overrideType) const2723 void MidiTrack::getMapItem(int patch, int index, DrumMap& dest_map, int overrideType) const
2724 {
2725 //if(!isDrumTrack())
2726 if(type() != DRUM)
2727 {
2728 dest_map = iNewDrumMap[index];
2729 return;
2730 }
2731 const int port = outPort();
2732 if(port < 0 || port >= MusECore::MIDI_PORTS)
2733 {
2734 dest_map = iNewDrumMap[index];
2735 return;
2736 }
2737 const MidiPort* mp = &MusEGlobal::midiPorts[port];
2738 const MidiInstrument* midi_instr = mp->instrument();
2739 if(!midi_instr)
2740 {
2741 dest_map = iNewDrumMap[index];
2742 return;
2743 }
2744
2745 // Get the instrument's map item, and include any requested overrides.
2746 const int channel = outChannel();
2747 midi_instr->getMapItem(channel, patch, index, dest_map, overrideType);
2748
2749 // Did we request to include any track default patch overrides?
2750 if(overrideType & WorkingDrumMapEntry::TrackDefaultOverride)
2751 {
2752 // Get any track default patch overrides.
2753 const WorkingDrumMapEntry* def_wdm = _workingDrumMapPatchList->find(CTRL_PROGRAM_VAL_DONT_CARE, index, false); // No default.
2754 if(def_wdm)
2755 {
2756 if(def_wdm->_fields & WorkingDrumMapEntry::NameField)
2757 dest_map.name = def_wdm->_mapItem.name;
2758
2759 if(def_wdm->_fields & WorkingDrumMapEntry::VolField)
2760 dest_map.vol = def_wdm->_mapItem.vol;
2761
2762 if(def_wdm->_fields & WorkingDrumMapEntry::QuantField)
2763 dest_map.quant = def_wdm->_mapItem.quant;
2764
2765 if(def_wdm->_fields & WorkingDrumMapEntry::LenField)
2766 dest_map.len = def_wdm->_mapItem.len;
2767
2768 if(def_wdm->_fields & WorkingDrumMapEntry::ChanField)
2769 dest_map.channel = def_wdm->_mapItem.channel;
2770
2771 if(def_wdm->_fields & WorkingDrumMapEntry::PortField)
2772 dest_map.port = def_wdm->_mapItem.port;
2773
2774 if(def_wdm->_fields & WorkingDrumMapEntry::Lv1Field)
2775 dest_map.lv1 = def_wdm->_mapItem.lv1;
2776
2777 if(def_wdm->_fields & WorkingDrumMapEntry::Lv2Field)
2778 dest_map.lv2 = def_wdm->_mapItem.lv2;
2779
2780 if(def_wdm->_fields & WorkingDrumMapEntry::Lv3Field)
2781 dest_map.lv3 = def_wdm->_mapItem.lv3;
2782
2783 if(def_wdm->_fields & WorkingDrumMapEntry::Lv4Field)
2784 dest_map.lv4 = def_wdm->_mapItem.lv4;
2785
2786 if(def_wdm->_fields & WorkingDrumMapEntry::ENoteField)
2787 dest_map.enote = def_wdm->_mapItem.enote;
2788
2789 if(def_wdm->_fields & WorkingDrumMapEntry::ANoteField)
2790 dest_map.anote = def_wdm->_mapItem.anote;
2791
2792 if(def_wdm->_fields & WorkingDrumMapEntry::MuteField)
2793 dest_map.mute = def_wdm->_mapItem.mute;
2794
2795 if(def_wdm->_fields & WorkingDrumMapEntry::HideField)
2796 dest_map.hide = def_wdm->_mapItem.hide;
2797 }
2798 }
2799
2800 // Did we request to include any track overrides?
2801 if(!(overrideType & WorkingDrumMapEntry::TrackOverride))
2802 return;
2803
2804 // Get any track overrides.
2805 const WorkingDrumMapEntry* wdm = _workingDrumMapPatchList->find(patch, index, false); // No default.
2806 if(!wdm)
2807 return;
2808
2809 if(wdm->_fields & WorkingDrumMapEntry::NameField)
2810 dest_map.name = wdm->_mapItem.name;
2811
2812 if(wdm->_fields & WorkingDrumMapEntry::VolField)
2813 dest_map.vol = wdm->_mapItem.vol;
2814
2815 if(wdm->_fields & WorkingDrumMapEntry::QuantField)
2816 dest_map.quant = wdm->_mapItem.quant;
2817
2818 if(wdm->_fields & WorkingDrumMapEntry::LenField)
2819 dest_map.len = wdm->_mapItem.len;
2820
2821 if(wdm->_fields & WorkingDrumMapEntry::ChanField)
2822 dest_map.channel = wdm->_mapItem.channel;
2823
2824 if(wdm->_fields & WorkingDrumMapEntry::PortField)
2825 dest_map.port = wdm->_mapItem.port;
2826
2827 if(wdm->_fields & WorkingDrumMapEntry::Lv1Field)
2828 dest_map.lv1 = wdm->_mapItem.lv1;
2829
2830 if(wdm->_fields & WorkingDrumMapEntry::Lv2Field)
2831 dest_map.lv2 = wdm->_mapItem.lv2;
2832
2833 if(wdm->_fields & WorkingDrumMapEntry::Lv3Field)
2834 dest_map.lv3 = wdm->_mapItem.lv3;
2835
2836 if(wdm->_fields & WorkingDrumMapEntry::Lv4Field)
2837 dest_map.lv4 = wdm->_mapItem.lv4;
2838
2839 if(wdm->_fields & WorkingDrumMapEntry::ENoteField)
2840 dest_map.enote = wdm->_mapItem.enote;
2841
2842 if(wdm->_fields & WorkingDrumMapEntry::ANoteField)
2843 dest_map.anote = wdm->_mapItem.anote;
2844
2845 if(wdm->_fields & WorkingDrumMapEntry::MuteField)
2846 dest_map.mute = wdm->_mapItem.mute;
2847
2848 if(wdm->_fields & WorkingDrumMapEntry::HideField)
2849 dest_map.hide = wdm->_mapItem.hide;
2850 }
2851
isWorkingMapItem(int index,int fields,int patch) const2852 int MidiTrack::isWorkingMapItem(int index, int fields, int patch) const
2853 {
2854 int ret = WorkingDrumMapEntry::NoOverride;
2855 if(type() != DRUM)
2856 return ret;
2857
2858 // Is there an instrument override for this drum map item?
2859 const int port = outPort();
2860 if(port >= 0 && port < MusECore::MIDI_PORTS)
2861 {
2862 const MidiPort* mp = &MusEGlobal::midiPorts[port];
2863 // Grab the patch number while we are here, if we asked for it.
2864 if(patch == -1)
2865 {
2866 const int chan = outChannel();
2867 patch = mp->hwCtrlState(chan, CTRL_PROGRAM);
2868 }
2869 #ifdef _USE_INSTRUMENT_OVERRIDES_
2870 const MidiInstrument* midi_instr = mp->instrument();
2871 if(midi_instr)
2872 ret |= midi_instr->isWorkingMapItem(patch, index, fields);
2873 #endif
2874 }
2875
2876 // Is there a local track default patch override for this drum map item?
2877 const WorkingDrumMapEntry* def_wdm = _workingDrumMapPatchList->find(CTRL_PROGRAM_VAL_DONT_CARE, index, false); // No default.
2878 if(def_wdm && (def_wdm->_fields & fields))
2879 ret |= WorkingDrumMapEntry::TrackDefaultOverride;
2880
2881 if(patch != -1)
2882 {
2883 // Is there a local track override for this drum map item?
2884 const WorkingDrumMapEntry* wdm = _workingDrumMapPatchList->find(patch, index, false); // No default.
2885 if(wdm && (wdm->_fields & fields))
2886 ret |= WorkingDrumMapEntry::TrackOverride;
2887 }
2888
2889 return ret;
2890 }
2891
normalizeDrumMap(int patch)2892 bool MidiTrack::normalizeDrumMap(int patch)
2893 {
2894 if(type() != DRUM)
2895 return false;
2896 //WorkingDrumMapList* wdml = _workingDrumMapPatchList->find(patch, true);
2897 WorkingDrumMapList* wdml = _workingDrumMapPatchList->find(patch, false);
2898 WorkingDrumMapList* def_wdml = 0;
2899 if(patch != CTRL_PROGRAM_VAL_DONT_CARE)
2900 def_wdml = _workingDrumMapPatchList->find(CTRL_PROGRAM_VAL_DONT_CARE, false);
2901
2902 int index = 0;
2903 DrumMap dm;
2904 char enote;
2905 bool changed = false;
2906
2907 bool used_index[128];
2908 int used_enotes[128];
2909 for(int i = 0; i < 128; ++i)
2910 {
2911 used_index[i] = false;
2912 used_enotes[i] = 0;
2913 }
2914 char unused_enotes[128];
2915 int unused_enotes_sz = 0;
2916 char unused_index[128];
2917 int unused_index_sz = 0;
2918 int unused_enotes_cnt = 0;
2919
2920 // Find all the used enote fields and their indexes in the working list.
2921 if(wdml)
2922 {
2923 for(iWorkingDrumMapPatch_t iwdml = wdml->begin(); iwdml != wdml->end(); ++iwdml)
2924 {
2925 WorkingDrumMapEntry& wdme = iwdml->second;
2926 if(wdme._fields & WorkingDrumMapEntry::ENoteField)
2927 {
2928 used_index[iwdml->first] = true;
2929 //++used_enotes[(unsigned char)wdme._mapItem.enote];
2930 }
2931 }
2932 }
2933
2934 // Add all the used enote fields and their indexes in the default patch working list.
2935 if(def_wdml)
2936 {
2937 for(iWorkingDrumMapPatch_t iwdml = def_wdml->begin(); iwdml != def_wdml->end(); ++iwdml)
2938 {
2939 WorkingDrumMapEntry& wdme = iwdml->second;
2940 if(wdme._fields & WorkingDrumMapEntry::ENoteField)
2941 {
2942 used_index[iwdml->first] = true;
2943 //++used_enotes[(unsigned char)wdme._mapItem.enote];
2944 }
2945 }
2946 }
2947
2948 // Find all the used enote fields and their indexes in the working list.
2949 if(wdml)
2950 {
2951 for(iWorkingDrumMapPatch_t iwdml = wdml->begin(); iwdml != wdml->end(); ++iwdml)
2952 {
2953 WorkingDrumMapEntry& wdme = iwdml->second;
2954 if(wdme._fields & WorkingDrumMapEntry::ENoteField)
2955 {
2956 //used_index[iwdml->first] = true;
2957 ++used_enotes[(unsigned char)wdme._mapItem.enote];
2958 }
2959 }
2960 }
2961
2962 // Find all the unused indexes and enotes so far in the working list.
2963 unused_index_sz = 0;
2964 unused_enotes_sz = 0;
2965 for(int i = 0; i < 128; ++i)
2966 {
2967 if(!used_index[i])
2968 unused_index[unused_index_sz++] = i;
2969 if(used_enotes[i] == 0)
2970 unused_enotes[unused_enotes_sz++] = i;
2971 }
2972
2973 // Ensure there are NO duplicate enotes in the existing working list items so far.
2974 unused_enotes_cnt = 0;
2975 if(wdml)
2976 {
2977 for(iWorkingDrumMapPatch_t iwdml = wdml->begin(); iwdml != wdml->end(); ++iwdml)
2978 {
2979 WorkingDrumMapEntry& wdme = iwdml->second;
2980 if(wdme._fields & WorkingDrumMapEntry::ENoteField)
2981 {
2982 // More than 1 (this) usage?
2983 if(used_enotes[(unsigned char)wdme._mapItem.enote] > 1)
2984 {
2985 fprintf(stderr, "MidiTrack::normalizeWorkingDrumMap: Warning: Duplicate enote:%d found. Overriding it.\n",
2986 wdme._mapItem.enote);
2987 if(unused_enotes_cnt >= unused_enotes_sz)
2988 {
2989 fprintf(stderr, "MidiTrack::normalizeWorkingDrumMap: Error: unused_enotes_cnt >= unused_enotes_sz:%d\n",
2990 unused_enotes_sz);
2991 break;
2992 }
2993 --used_enotes[(unsigned char)wdme._mapItem.enote];
2994 //wdme._mapItem.enote = unused_enotes[unused_enotes_cnt++];
2995 // Get the instrument item.
2996 index = iwdml->first;
2997 // Modify the enote field.
2998 enote = unused_enotes[unused_enotes_cnt++];
2999 _drummap[index].enote = enote;
3000 ++used_enotes[(unsigned char)enote];
3001 changed = true;
3002 }
3003 }
3004 }
3005 }
3006
3007 // Find all the used enote fields and their indexes in the default patch working list.
3008 if(def_wdml)
3009 {
3010 for(iWorkingDrumMapPatch_t iwdml = def_wdml->begin(); iwdml != def_wdml->end(); ++iwdml)
3011 {
3012 WorkingDrumMapEntry& wdme = iwdml->second;
3013 if(wdme._fields & WorkingDrumMapEntry::ENoteField)
3014 {
3015 //used_index[iwdml->first] = true;
3016 // If there is already a non-default patch enote override for this index,
3017 // do not increment used_notes, the non-default one takes priority over this default one.
3018 if(wdml)
3019 {
3020 ciWorkingDrumMapPatch_t def_iwdml = wdml->find(iwdml->first);
3021 if(def_iwdml != wdml->end())
3022 {
3023 const WorkingDrumMapEntry& def_wdme = def_iwdml->second;
3024 if(def_wdme._fields & WorkingDrumMapEntry::ENoteField)
3025 continue;
3026 }
3027 }
3028 ++used_enotes[(unsigned char)wdme._mapItem.enote];
3029 }
3030 }
3031 }
3032
3033 // Find all the unused indexes and enotes so far in the working list.
3034 unused_enotes_sz = 0;
3035 for(int i = 0; i < 128; ++i)
3036 {
3037 if(used_enotes[i] == 0)
3038 unused_enotes[unused_enotes_sz++] = i;
3039 }
3040
3041 // Ensure there are NO duplicate enotes in the existing default patch working list items so far.
3042 unused_enotes_cnt = 0;
3043 if(def_wdml)
3044 {
3045 for(iWorkingDrumMapPatch_t iwdml = def_wdml->begin(); iwdml != def_wdml->end(); ++iwdml)
3046 {
3047 WorkingDrumMapEntry& wdme = iwdml->second;
3048 if(wdme._fields & WorkingDrumMapEntry::ENoteField)
3049 {
3050 // If there is already a non-default patch enote override for this index,
3051 // skip this one, the non-default one takes priority over this default one.
3052 if(wdml)
3053 {
3054 ciWorkingDrumMapPatch_t def_iwdml = wdml->find(iwdml->first);
3055 if(def_iwdml != wdml->end())
3056 {
3057 const WorkingDrumMapEntry& def_wdme = def_iwdml->second;
3058 if(def_wdme._fields & WorkingDrumMapEntry::ENoteField)
3059 continue;
3060 }
3061 }
3062
3063 // More than 1 (this) usage?
3064 if(used_enotes[(unsigned char)wdme._mapItem.enote] > 1)
3065 {
3066 fprintf(stderr, "MidiTrack::normalizeWorkingDrumMap: Warning: Duplicate default enote:%d found. Overriding it.\n",
3067 wdme._mapItem.enote);
3068 if(unused_enotes_cnt >= unused_enotes_sz)
3069 {
3070 fprintf(stderr, "MidiTrack::normalizeWorkingDrumMap: Error: Default unused_enotes_cnt >= unused_enotes_sz:%d\n",
3071 unused_enotes_sz);
3072 break;
3073 }
3074 --used_enotes[(unsigned char)wdme._mapItem.enote];
3075 //wdme._mapItem.enote = unused_enotes[unused_enotes_cnt++];
3076 // Get the instrument item.
3077 index = iwdml->first;
3078 // Modify the enote field.
3079 enote = unused_enotes[unused_enotes_cnt++];
3080 _drummap[index].enote = enote;
3081 ++used_enotes[(unsigned char)enote];
3082 changed = true;
3083 }
3084 }
3085 }
3086 }
3087
3088 // Add all used enotes in the unused enote indexes (the instrument fields).
3089 for(int i = 0; i < unused_index_sz; ++i)
3090 ++used_enotes[(unsigned char)_drummap[(unsigned char)unused_index[i]].enote];
3091
3092 // Find all the unused enotes.
3093 unused_enotes_sz = 0;
3094 for(int i = 0; i < 128; ++i)
3095 {
3096 if(used_enotes[i] == 0)
3097 unused_enotes[unused_enotes_sz++] = i;
3098 }
3099
3100 // Ensure there are NO duplicate enotes in the unused enote map fields (the instrument fields).
3101 unused_enotes_cnt = 0;
3102 for(int i = 0; i < unused_index_sz; ++i)
3103 {
3104 // Get the instrument item.
3105 index = unused_index[i];
3106 enote = _drummap[index].enote;
3107
3108 // More than 1 (this) usage?
3109 if(used_enotes[(unsigned char)enote] > 1)
3110 {
3111 if(unused_enotes_cnt >= unused_enotes_sz)
3112 {
3113 fprintf(stderr, "MidiTrack::normalizeWorkingDrumMap: Error filling background items: unused_enotes_cnt >= unused_enotes_sz:%d\n",
3114 unused_enotes_sz);
3115 break;
3116 }
3117
3118 --used_enotes[(unsigned char)enote];
3119
3120 // Modify the enote field.
3121 _drummap[index].enote = unused_enotes[unused_enotes_cnt++];
3122 ++used_enotes[(unsigned char)_drummap[index].enote];
3123 changed = true;
3124 }
3125 }
3126
3127 return changed;
3128 }
3129
normalizeDrumMap()3130 bool MidiTrack::normalizeDrumMap()
3131 {
3132 if(type() != DRUM)
3133 return false;
3134 const int port = outPort();
3135 if(port < 0 || port >= MusECore::MIDI_PORTS)
3136 return false;
3137 const int chan = outChannel();
3138 const int patch = MusEGlobal::midiPorts[port].hwCtrlState(chan, MusECore::CTRL_PROGRAM);
3139 return normalizeDrumMap(patch);
3140 }
3141
3142 } // namespace MusECore
3143