1 //=========================================================
2 // MusE
3 // Linux Music Editor
4 // $Id: midictrl.cpp,v 1.17.2.10 2009/06/10 00:34:59 terminator356 Exp $
5 //
6 // (C) Copyright 2001-2004 Werner Schweer (ws@seh.de)
7 // (C) Copyright 2012 Tim E. Real (terminator356 on users dot sourceforge dot net)
8 //
9 // This program is free software; you can redistribute it and/or
10 // modify it under the terms of the GNU General Public License
11 // as published by the Free Software Foundation; version 2 of
12 // the License, or (at your option) any later version.
13 //
14 // This program is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 // GNU General Public License for more details.
18 //
19 // You should have received a copy of the GNU General Public License
20 // along with this program; if not, write to the Free Software
21 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 //
23 //=========================================================
24
25 #include <cstdio>
26
27 #include "midi_controller.h"
28
29 namespace MusECore {
30
31 static const char* ctrlName[] = {
32 "BankSelMSB", "Modulation", "BreathCtrl", "Control 3", "Foot Ctrl",
33 "Porta Time", "DataEntMSB", "MainVolume", "Balance", "Control 9",
34 /*10*/ "Pan", "Expression", "Control 12", "Control 13", "Control 14",
35 "Control 15", "Gen.Purp.1", "Gen.Purp.2", "Gen.Purp.3", "Gen.Purp.4",
36 /*20*/ "Control 20", "Control 21", "Control 22", "Control 23", "Control 24",
37 "Control 25", "Control 26", "Control 27", "Control 28", "Control 29",
38 /*30*/ "Control 30", "Control 31", "BankSelLSB", "Modul. LSB", "BrthCt.LSB",
39 "Control 35", "FootCt.LSB", "Port.T LSB", "DataEntLSB", "MainVolLSB",
40 "BalanceLSB", "Control 41", "Pan LSB", "Expr. LSB", "Control 44",
41 "Control 45", "Control 46", "Control 47", "Gen.P.1LSB", "Gen.P.2LSB",
42 /*50*/ "Gen.P.3LSB", "Gen.P.4LSB", "Control 52", "Control 53", "Control 54",
43 "Control 55", "Control 56", "Control 57", "Control 58", "Control 59",
44 "Control 60", "Control 61", "Control 62", "Control 63", "Sustain",
45 "Porta Ped", "Sostenuto", "Soft Pedal", "Control 68", "Hold 2",
46 "Control 70", "HarmonicCo", "ReleaseTime", "Attack Time", "Brightness",
47 "Control 75", "Control 76", "Control 77", "Control 78", "Control 79",
48 "Gen.Purp.5", "Gen.Purp.6", "Gen.Purp.7", "Gen.Purp.8", "Porta Ctrl",
49 "Control 85", "Control 86", "Control 87", "Control 88", "Control 89",
50 "Control 90", "Effect1Dep", "Effect2Dep", "Effect3Dep", "Effect4Dep",
51 "Phaser Dep", "Data Incr", "Data Decr", "NRPN LSB", "NRPN MSB",
52 /*100*/ "RPN LSB", "RPN MSB", "Control102", "Control103", "Control104",
53 "Control105", "Control106", "Control107", "Control108", "Control109",
54 "Control110", "Control111", "Control112", "Control113", "Control114",
55 "Control115", "Control116", "Control117", "Control118", "Control119",
56 "AllSndOff", "Reset Ctrl", "Local Ctrl", "AllNoteOff", "OmniModOff",
57 "OmniModeOn", "MonoModeOn", "PolyModeOn"
58 };
59
60 #if 0
61 static const char* ctrl14Name[] = {
62 "BankSel", "Modulation", "BreathCtrl",
63 "Control 3", "Foot Ctrl", "Porta Time", "DataEntry",
64 "MainVolume", "Balance", "Control 9", "Pan",
65 "Expression", "Control 12", "Control 13", "Control 14",
66 "Control 15", "Gen.Purp.1", "Gen.Purp.2", "Gen.Purp.3",
67 "Gen.Purp.4", "Control 20", "Control 21", "Control 22",
68 "Control 23", "Control 24", "Control 25", "Control 26",
69 "Control 27", "Control 28", "Control 29", "Control 30",
70 "Control 31",
71 };
72 #endif
73
74 //---------------------------------------------------------
75 // ctrlType2Int
76 // int2ctrlType
77 //---------------------------------------------------------
78
79 static struct {
80 MidiController::ControllerType type;
81 QString name;
82 } ctrlTypes[] = {
83 { MidiController::Controller7, QString("Control7") },
84 { MidiController::Controller14, QString("Control14") },
85 { MidiController::RPN, QString("RPN") },
86 { MidiController::NRPN, QString("NRPN") },
87 { MidiController::RPN14, QString("RPN14") },
88 { MidiController::NRPN14, QString("NRPN14") },
89 { MidiController::Pitch, QString("Pitch") },
90 { MidiController::Program, QString("Program") },
91 { MidiController::PolyAftertouch, QString("PolyAftertouch") },
92 { MidiController::Aftertouch, QString("Aftertouch") },
93 { MidiController::Controller7, QString("Control") }, // alias
94 };
95
96 //---------------------------------------------------------
97 // ctrlType2Int
98 //---------------------------------------------------------
99
ctrlType2Int(const QString & s)100 MidiController::ControllerType ctrlType2Int(const QString& s)
101 {
102 int n = sizeof(ctrlTypes)/sizeof(*ctrlTypes);
103 for (int i = 0; i < n; ++i) {
104 if (ctrlTypes[i].name == s)
105 return ctrlTypes[i].type;
106 }
107 return MidiController::ControllerType(0);
108 }
109
110 //---------------------------------------------------------
111 // int2ctrlType
112 //---------------------------------------------------------
113
int2ctrlType(int n)114 const QString& int2ctrlType(int n)
115 {
116 static QString dontKnow("?T?");
117 int size = sizeof(ctrlTypes)/sizeof(*ctrlTypes);
118 for (int i = 0; i < size; ++i) {
119 if (ctrlTypes[i].type == n)
120 return ctrlTypes[i].name;
121 }
122 return dontKnow;
123 }
124
125 //---------------------------------------------------------
126 // midiCtrlNumString
127 //---------------------------------------------------------
128
midiCtrlNumString(int ctrl,bool fullyQualified)129 QString midiCtrlNumString(int ctrl, bool fullyQualified)
130 {
131 int h = (ctrl >> 8) & 0xff;
132 int l = ctrl & 0xff;
133 QString s1 = QString("%1").arg(h);
134 QString s2 = ( l == 0xff ? QString("* ") : QString("%1 ").arg(l) );
135 MidiController::ControllerType type = midiControllerType(ctrl);
136 switch (type)
137 {
138 case MidiController::Controller7:
139 if(fullyQualified)
140 return s2;
141 else
142 return QString();
143 case MidiController::Controller14:
144 return s1 + QString("CF") + s2;
145 case MidiController::RPN:
146 return s1 + QString("R") + s2;
147 case MidiController::NRPN:
148 return s1 + QString("N") + s2;
149 case MidiController::Pitch: // Don't show internal controller numbers.
150 case MidiController::Program:
151 case MidiController::Velo:
152 case MidiController::PolyAftertouch:
153 case MidiController::Aftertouch:
154 return QString();
155 case MidiController::RPN14:
156 return s1 + QString("RF") + s2;
157 case MidiController::NRPN14:
158 return s1 + QString("NF") + s2;
159 }
160 return s1 + QString("?") + s2;
161 }
162
163 //---------------------------------------------------------
164 // midiCtrlName
165 //---------------------------------------------------------
166
midiCtrlName(int ctrl,bool fullyQualified)167 QString midiCtrlName(int ctrl, bool fullyQualified)
168 {
169 int h = (ctrl >> 8) & 0xff;
170 int l = ctrl & 0xff;
171 QString s1 = QString("%1").arg(h);
172 QString s2 = ( l == 0xff ? QString("*") : QString("%1").arg(l) );
173 MidiController::ControllerType type = midiControllerType(ctrl);
174 switch (type)
175 {
176 case MidiController::Controller7:
177 if(fullyQualified)
178 return s2 + QString(" ") + QString(ctrlName[l]);
179 else
180 return QString(ctrlName[l]);
181 case MidiController::Controller14:
182 return s1 + QString("CF") + s2;
183 case MidiController::RPN:
184 return s1 + QString("R") + s2;
185 case MidiController::NRPN:
186 return s1 + QString("N") + s2;
187 case MidiController::Pitch:
188 return QString("Pitch");
189 case MidiController::Program:
190 return QString("Program");
191 case MidiController::Velo:
192 return QString("Velocity");
193 case MidiController::PolyAftertouch:
194 return QString("PolyAftertouch");
195 case MidiController::Aftertouch:
196 return QString("Aftertouch");
197 case MidiController::RPN14:
198 return s1 + QString("RF") + s2;
199 case MidiController::NRPN14:
200 return s1 + QString("NF") + s2;
201 }
202 return s1 + QString("?") + s2;
203 }
204
205 //---------------------------------------------------------
206 // MidiController
207 //---------------------------------------------------------
208
MidiController()209 MidiController::MidiController()
210 : _name(QString("Velocity"))
211 {
212 _num = CTRL_VELOCITY;
213 // Zero note on vel is not allowed now.
214 _minVal = 1;
215 _maxVal = 127;
216 _initVal = _drumInitVal = 0;
217 _showInTracks = ShowInDrum | ShowInMidi;
218 updateBias();
219 }
220
MidiController(const QString & s,int n,int min,int max,int init,int drumInit,int show_in_track)221 MidiController::MidiController(const QString& s, int n, int min, int max, int init, int drumInit, int show_in_track)
222 : _name(s), _num(n), _minVal(min), _maxVal(max), _initVal(init), _showInTracks(show_in_track)
223 {
224 // If drumInit was given, use it otherwise set it to the normal init val.
225 if(drumInit != -1)
226 _drumInitVal = drumInit;
227 else
228 _drumInitVal = _initVal;
229 updateBias();
230 }
231
MidiController(const MidiController & mc)232 MidiController::MidiController(const MidiController& mc)
233 {
234 copy(mc);
235 }
236
237 //---------------------------------------------------------
238 // copy
239 //---------------------------------------------------------
240
copy(const MidiController & mc)241 void MidiController::copy(const MidiController &mc)
242 {
243 _name = mc._name;
244 _num = mc._num;
245 _minVal = mc._minVal;
246 _maxVal = mc._maxVal;
247 _initVal = mc._initVal;
248 _drumInitVal = mc._drumInitVal;
249 _bias = mc._bias;
250 _showInTracks = mc._showInTracks;
251 }
252
253 //---------------------------------------------------------
254 // operator =
255 //---------------------------------------------------------
256
operator =(const MidiController & mc)257 MidiController& MidiController::operator=(const MidiController &mc)
258 {
259 copy(mc);
260 return *this;
261 }
262
263 //---------------------------------------------------------
264 // type
265 //---------------------------------------------------------
266
midiControllerType(int num)267 MidiController::ControllerType midiControllerType(int num)
268 {
269 if (num < CTRL_14_OFFSET)
270 return MidiController::Controller7;
271 if (num < CTRL_RPN_OFFSET)
272 return MidiController::Controller14;
273 if (num < CTRL_NRPN_OFFSET)
274 return MidiController::RPN;
275 if (num < CTRL_INTERNAL_OFFSET)
276 return MidiController::NRPN;
277 if (num == CTRL_PITCH)
278 return MidiController::Pitch;
279 if (num == CTRL_PROGRAM)
280 return MidiController::Program;
281 if (num == CTRL_VELOCITY)
282 return MidiController::Velo;
283 if ((num | 0xff) == CTRL_POLYAFTER)
284 return MidiController::PolyAftertouch;
285 if (num == CTRL_AFTERTOUCH)
286 return MidiController::Aftertouch;
287 if (num < CTRL_NRPN14_OFFSET)
288 return MidiController::RPN14;
289 if (num < CTRL_NONE_OFFSET)
290 return MidiController::NRPN14;
291 return MidiController::Controller7;
292 }
293
294 //---------------------------------------------------------
295 // midiCtrlTerms2Number
296 //---------------------------------------------------------
297
midiCtrlTerms2Number(MidiController::ControllerType type,int ctrl)298 int midiCtrlTerms2Number(MidiController::ControllerType type, int ctrl)
299 {
300 ctrl &= 0xffff;
301 switch(type)
302 {
303 case MidiController::Controller7:
304 return ctrl & 0xff;
305 case MidiController::Controller14:
306 return CTRL_14_OFFSET + ctrl;
307 case MidiController::RPN:
308 return CTRL_RPN_OFFSET + ctrl;
309 case MidiController::NRPN:
310 return CTRL_NRPN_OFFSET + ctrl;
311 case MidiController::Pitch:
312 return CTRL_PITCH;
313 case MidiController::Program:
314 return CTRL_PROGRAM;
315 case MidiController::Velo:
316 return CTRL_VELOCITY;
317 case MidiController::PolyAftertouch:
318 return CTRL_POLYAFTER;
319 case MidiController::Aftertouch:
320 return CTRL_AFTERTOUCH;
321 case MidiController::RPN14:
322 return CTRL_RPN14_OFFSET + ctrl;
323 case MidiController::NRPN14:
324 return CTRL_NRPN14_OFFSET + ctrl;
325 default:
326 printf("MusE: unknown ctrl type in midiCtrTerms2Number()\n");
327 return ctrl;
328 }
329 }
330
331
332 //---------------------------------------------------------
333 // isPerNoteMidiController
334 //---------------------------------------------------------
335
isPerNoteMidiController(int ctl)336 bool isPerNoteMidiController(int ctl)
337 {
338 const int n = ctl & 0xff0000;
339 return ctl == CTRL_POLYAFTER ||
340 ((ctl & 0xff) == 0xff &&
341 (n == CTRL_RPN_OFFSET ||
342 n == CTRL_NRPN_OFFSET ||
343 n == CTRL_RPN14_OFFSET ||
344 n == CTRL_NRPN14_OFFSET));
345 }
346
347 //---------------------------------------------------------
348 // isPerNoteController
349 //---------------------------------------------------------
350
isPerNoteController() const351 bool MidiController::isPerNoteController() const
352 {
353 return isPerNoteMidiController(num());
354 }
355
356 //---------------------------------------------------------
357 // type
358 //---------------------------------------------------------
359
type() const360 MidiController::ControllerType MidiController::type() const
361 {
362 return midiControllerType(num());
363 }
364
365 //---------------------------------------------------------
366 // updateBias
367 //---------------------------------------------------------
368
updateBias()369 void MidiController::updateBias()
370 {
371 // If the specified minimum value is negative, we will
372 // translate to a positive-biased range.
373 // Cue: A controller like 'coarse tuning', is meant to be displayed
374 // as -24/+24, but really is centered on 64 and goes from 40 to 88.
375 int b;
376 int mn, mx;
377 ControllerType t = midiControllerType(_num);
378 switch (t)
379 {
380 case RPN:
381 case NRPN:
382 case Controller7:
383 b = 64;
384 mn = 0;
385 mx = 127;
386 break;
387 case Controller14:
388 case RPN14:
389 case NRPN14:
390 b = 8192;
391 mn = 0;
392 mx = 16383;
393 break;
394 case Program:
395 b = 0x800000;
396 mn = 0;
397 mx = 0xffffff;
398 break;
399 case Pitch:
400 b = 0;
401 mn = -8192;
402 mx = 8191;
403 break;
404 //case Velo: // cannot happen
405 //case PolyAfter:
406 //case After:
407 default:
408 b = 64;
409 mn = 0;
410 mx = 127;
411 break;
412 }
413
414 // TODO: Limit _minVal and _maxVal to range.
415
416 if(_minVal >= 0)
417 _bias = 0;
418 else
419 {
420 _bias = b;
421
422 if(t != Program && t != Pitch)
423 {
424 // Adjust bias to fit desired range.
425 if(_minVal + _bias < mn)
426 _bias += mn - _minVal + _bias;
427 else
428 if(_maxVal + _bias > mx)
429 _bias -= _maxVal + _bias - mx;
430 }
431 }
432 }
433
434
435 //---------------------------------------------------------
436 // MidiController::write
437 //---------------------------------------------------------
438
write(int level,Xml & xml) const439 void MidiController::write(int level, Xml& xml) const
440 {
441 ControllerType t = midiControllerType(_num);
442 if(t == Velo)
443 return;
444
445 QString type(int2ctrlType(t));
446
447 int h = (_num >> 8) & 0x7f;
448 int l = _num & 0x7f;
449
450 QString sl;
451 if (isPerNoteController())
452 sl = "pitch";
453 else
454 sl.setNum(l);
455
456 xml.nput(level, "<Controller name=\"%s\"", Xml::xmlString(_name).toLatin1().constData());
457 if(t != Controller7)
458 xml.nput(" type=\"%s\"", type.toLatin1().constData());
459
460 int mn = 0;
461 int mx = 0;
462 switch (t)
463 {
464 case RPN:
465 case NRPN:
466 xml.nput(" h=\"%d\"", h);
467 xml.nput(" l=\"%s\"", sl.toLatin1().constData());
468 mx = 127;
469 break;
470 case Controller7:
471 xml.nput(" l=\"%s\"", sl.toLatin1().constData());
472 mx = 127;
473 break;
474 case Controller14:
475 case RPN14:
476 case NRPN14:
477 xml.nput(" h=\"%d\"", h);
478 xml.nput(" l=\"%s\"", sl.toLatin1().constData());
479 mx = 16383;
480 break;
481 case Pitch:
482 mn = -8192;
483 mx = 8191;
484 break;
485 case PolyAftertouch:
486 mn = 0;
487 mx = 127;
488 break;
489 case Aftertouch:
490 mn = 0;
491 mx = 127;
492 break;
493 case Program:
494 case Velo: // Cannot happen
495 break;
496 }
497
498 if(t == Program)
499 {
500 if(_initVal != CTRL_VAL_UNKNOWN && _initVal != 0xffffff)
501 xml.nput(" init=\"0x%x\"", _initVal);
502 if(_drumInitVal != CTRL_VAL_UNKNOWN && _drumInitVal != 0xffffff)
503 xml.nput(" drumInit=\"0x%x\"", _drumInitVal);
504 }
505 else
506 {
507 if(_minVal != mn)
508 xml.nput(" min=\"%d\"", _minVal);
509 if(_maxVal != mx)
510 xml.nput(" max=\"%d\"", _maxVal);
511
512 if(_initVal != CTRL_VAL_UNKNOWN)
513 xml.nput(" init=\"%d\"", _initVal);
514 if(_drumInitVal != CTRL_VAL_UNKNOWN)
515 xml.nput(" drumInit=\"%d\"", _drumInitVal);
516 }
517
518 if(_showInTracks != (ShowInDrum | ShowInMidi))
519 xml.nput(" showType=\"%d\"", _showInTracks);
520
521 xml.put(" />");
522 }
523
524 //---------------------------------------------------------
525 // MidiController::read
526 //---------------------------------------------------------
527
read(Xml & xml)528 void MidiController::read(Xml& xml)
529 {
530 ControllerType t = Controller7;
531 _initVal = CTRL_VAL_UNKNOWN;
532 int drum_init = -1; // -1 = Not set yet.
533 static const int NOT_SET = 0x100000;
534 _minVal = NOT_SET;
535 _maxVal = NOT_SET;
536 int h = 0;
537 int l = 0;
538 bool ok;
539 int base = 10;
540
541 for (;;) {
542 Xml::Token token = xml.parse();
543 const QString& tag = xml.s1();
544 switch (token) {
545 case Xml::Error:
546 case Xml::End:
547 goto mc_read_end;
548 case Xml::Attribut:
549 {
550 QString s = xml.s2();
551 if (s.left(2) == "0x")
552 base = 16;
553 if (tag == "name")
554 _name = xml.s2();
555 else if (tag == "type")
556 t = ctrlType2Int(xml.s2());
557 else if (tag == "h")
558 h = xml.s2().toInt(&ok, base);
559 else if (tag == "l") {
560 // Support instrument files with '*' or 'pitch' as wildcard.
561 if ((xml.s2() == "*") || (xml.s2() == "pitch"))
562 l = 0xff;
563 else
564 l = xml.s2().toInt(&ok, base);
565 }
566 else if (tag == "min")
567 _minVal = xml.s2().toInt(&ok, base);
568 else if (tag == "max")
569 _maxVal = xml.s2().toInt(&ok, base);
570 else if (tag == "init")
571 _initVal = xml.s2().toInt(&ok, base);
572 else if (tag == "drumInit")
573 drum_init = xml.s2().toInt(&ok, base);
574 else if (tag == "showType")
575 _showInTracks = xml.s2().toInt(&ok, base);
576 }
577 break;
578 case Xml::TagStart:
579 xml.unknown("MidiController");
580 break;
581 case Xml::TagEnd:
582 if (tag == "Controller") {
583 _num = (h << 8) + l;
584 switch (t) {
585 case RPN:
586 if (_maxVal == NOT_SET)
587 _maxVal = 127;
588 _num |= CTRL_RPN_OFFSET;
589 break;
590 case NRPN:
591 if (_maxVal == NOT_SET)
592 _maxVal = 127;
593 _num |= CTRL_NRPN_OFFSET;
594 break;
595 case Controller7:
596 if (_maxVal == NOT_SET)
597 _maxVal = 127;
598 break;
599 case Controller14:
600 _num |= CTRL_14_OFFSET;
601 if (_maxVal == NOT_SET)
602 _maxVal = 16383;
603 break;
604 case RPN14:
605 if (_maxVal == NOT_SET)
606 _maxVal = 16383;
607 _num |= CTRL_RPN14_OFFSET;
608 break;
609 case NRPN14:
610 if (_maxVal == NOT_SET)
611 _maxVal = 16383;
612 _num |= CTRL_NRPN14_OFFSET;
613 break;
614 case Pitch:
615 if (_maxVal == NOT_SET)
616 _maxVal = 8191;
617 if (_minVal == NOT_SET)
618 _minVal = -8192;
619 _num = CTRL_PITCH;
620 break;
621 case Program:
622 if (_maxVal == NOT_SET)
623 _maxVal = 0xffffff;
624 _num = CTRL_PROGRAM;
625 break;
626 case PolyAftertouch:
627 if (_maxVal == NOT_SET)
628 _maxVal = 127;
629 if (_minVal == NOT_SET)
630 _minVal = 0;
631 _num = CTRL_POLYAFTER;
632 break;
633 case Aftertouch:
634 if (_maxVal == NOT_SET)
635 _maxVal = 127;
636 if (_minVal == NOT_SET)
637 _minVal = 0;
638 _num = CTRL_AFTERTOUCH;
639 break;
640 case Velo: // cannot happen
641 break;
642 }
643 if (_minVal == NOT_SET)
644 _minVal = 0;
645 // No drum init val given? Use normal init val.
646 if(drum_init == -1)
647 _drumInitVal = _initVal;
648 else
649 _drumInitVal = drum_init;
650 updateBias();
651 return;
652 }
653 default:
654 break;
655 }
656 }
657
658 mc_read_end:
659 _drumInitVal = _initVal;
660 }
661
662 //---------------------------------------------------------
663 // genNum
664 //---------------------------------------------------------
665
genNum(MidiController::ControllerType t,int h,int l)666 int MidiController::genNum(MidiController::ControllerType t, int h, int l)
667 {
668 int val = (h << 8) | (l & 0xff);
669 switch(t) {
670 case Controller7:
671 return l & 0xff;
672 case Controller14:
673 return val + CTRL_14_OFFSET;
674 case RPN:
675 return val + CTRL_RPN_OFFSET;
676 case NRPN:
677 return val + CTRL_NRPN_OFFSET;
678 case RPN14:
679 return val + CTRL_RPN14_OFFSET;
680 case NRPN14:
681 return val + CTRL_NRPN14_OFFSET;
682 case Pitch:
683 return CTRL_PITCH;
684 case Program:
685 return CTRL_PROGRAM;
686 case PolyAftertouch:
687 return CTRL_POLYAFTER;
688 case Aftertouch:
689 return CTRL_AFTERTOUCH;
690 default:
691 return -1;
692 }
693 }
694
695 //---------------------------------------------------------
696 // MidiControllerList
697 //---------------------------------------------------------
698
MidiControllerList()699 MidiControllerList::MidiControllerList()
700 {
701 _RPN_Ctrls_Reserved = false;
702 }
703
MidiControllerList(const MidiControllerList & mcl)704 MidiControllerList::MidiControllerList(const MidiControllerList& mcl) : std::map<int, MidiController*>()
705 {
706 for(ciMidiController i = mcl.begin(); i != mcl.end(); ++i)
707 {
708 MidiController* mc = i->second;
709 add(new MidiController(*mc));
710 }
711 update_RPN_Ctrls_Reserved();
712 }
713
add(MidiController * mc,bool update)714 bool MidiControllerList::add(MidiController* mc, bool update)
715 {
716 const int num = mc->num();
717 if(!_RPN_Ctrls_Reserved && update)
718 {
719 const bool isCtl7 = ((num & CTRL_OFFSET_MASK) == CTRL_7_OFFSET);
720 const bool isCtl14 = ((num & CTRL_OFFSET_MASK) == CTRL_14_OFFSET);
721 if(isCtl14 || isCtl7)
722 {
723 const int l = num & 0xff;
724 if(l == CTRL_HDATA ||
725 l == CTRL_LDATA ||
726 l == CTRL_DATA_INC ||
727 l == CTRL_DATA_DEC ||
728 l == CTRL_HNRPN ||
729 l == CTRL_LNRPN ||
730 l == CTRL_HRPN ||
731 l == CTRL_LRPN)
732 _RPN_Ctrls_Reserved = true;
733 }
734 if(!_RPN_Ctrls_Reserved && isCtl14)
735 {
736 const int h = (num >> 8) & 0xff;
737 if(h == CTRL_HDATA ||
738 h == CTRL_LDATA ||
739 h == CTRL_DATA_INC ||
740 h == CTRL_DATA_DEC ||
741 h == CTRL_HNRPN ||
742 h == CTRL_LNRPN ||
743 h == CTRL_HRPN ||
744 h == CTRL_LRPN)
745 _RPN_Ctrls_Reserved = true;
746 }
747 }
748 return insert(MidiControllerListPair(num, mc)).second;
749 }
750
del(iMidiController ictl,bool update)751 void MidiControllerList::del(iMidiController ictl, bool update)
752 {
753 erase(ictl);
754 if(update)
755 update_RPN_Ctrls_Reserved();
756 }
757
del(int num,bool update)758 MidiControllerList::size_type MidiControllerList::del(int num, bool update)
759 {
760 MidiControllerList::size_type res = erase(num);
761 if(update)
762 update_RPN_Ctrls_Reserved();
763 return res;
764 }
765
del(iMidiController first,iMidiController last,bool update)766 void MidiControllerList::del(iMidiController first, iMidiController last, bool update)
767 {
768 erase(first, last);
769 if(update)
770 update_RPN_Ctrls_Reserved();
771 }
772
clr()773 void MidiControllerList::clr()
774 {
775 clear();
776 update_RPN_Ctrls_Reserved();
777 }
778
779 //---------------------------------------------------------
780 // update_RPN_Ctrls_Reserved
781 // Manual check and update of the flag. For convenience, returns the flag.
782 // Cost depends on types and number of list controllers, so it is good for deferring
783 // an update until AFTER some lengthy list operation. JUST BE SURE to call this!
784 //---------------------------------------------------------
785
update_RPN_Ctrls_Reserved()786 bool MidiControllerList::update_RPN_Ctrls_Reserved()
787 {
788 if(find(CTRL_HDATA) != end() ||
789 find(CTRL_LDATA) != end() ||
790 find(CTRL_DATA_INC) != end() ||
791 find(CTRL_DATA_DEC) != end() ||
792 find(CTRL_HNRPN) != end() ||
793 find(CTRL_LNRPN) != end() ||
794 find(CTRL_HRPN) != end() ||
795 find(CTRL_LRPN) != end())
796 {
797 _RPN_Ctrls_Reserved = true;
798 return true;
799 }
800
801 int num, h, l;
802 // Search: Get a head-start by taking lower bound.
803 for(iMidiController imc = lower_bound(CTRL_14_OFFSET); imc != end(); ++imc)
804 {
805 num = imc->second->num();
806 // Stop if we went beyond this ctrl14 block.
807 if((num & CTRL_OFFSET_MASK) != CTRL_14_OFFSET)
808 {
809 _RPN_Ctrls_Reserved = false;
810 return false;
811 }
812 h = (num >> 8) & 0xff;
813 l = num & 0xff;
814 if(h == CTRL_HDATA || l == CTRL_HDATA ||
815 h == CTRL_LDATA || l == CTRL_LDATA ||
816 h == CTRL_DATA_INC || l == CTRL_DATA_INC ||
817 h == CTRL_DATA_DEC || l == CTRL_DATA_DEC ||
818 h == CTRL_HNRPN || l == CTRL_HNRPN ||
819 h == CTRL_LNRPN || l == CTRL_LNRPN ||
820 h == CTRL_HRPN || l == CTRL_HRPN ||
821 h == CTRL_LRPN || l == CTRL_LRPN)
822 {
823 _RPN_Ctrls_Reserved = true;
824 return true;
825 }
826 }
827 _RPN_Ctrls_Reserved = false;
828 return false;
829 }
830
831 //---------------------------------------------------------
832 // Catch all insert, erase, clear etc.
833 //---------------------------------------------------------
834
operator =(const MidiControllerList & cl)835 MidiControllerList& MidiControllerList::operator=(const MidiControllerList& cl)
836 {
837 #ifdef _MIDI_CTRL_DEBUG_
838 printf("MidiControllerList::operator=\n");
839 #endif
840 _RPN_Ctrls_Reserved = cl._RPN_Ctrls_Reserved;
841
842 // Let map copy the items.
843 std::map<int, MidiController*, std::less<int> >::operator=(cl);
844 return *this;
845 }
846
847 //=========================================================
848 #ifdef _MIDI_CTRL_METHODS_DEBUG_
849
swap(MidiControllerList & cl)850 void MidiControllerList::swap(MidiControllerList& cl)
851 {
852 #ifdef _MIDI_CTRL_DEBUG_
853 printf("MidiControllerList::swap\n");
854 #endif
855 std::map<int, MidiController*, std::less<int> >::swap(cl);
856 }
857
insert(const std::pair<int,MidiController * > & p)858 std::pair<iMidiController, bool> MidiControllerList::insert(const std::pair<int, MidiController*>& p)
859 {
860 #ifdef _MIDI_CTRL_DEBUG_
861 printf("MidiControllerList::insert num:%d\n", p.second->num());
862 #endif
863 std::pair<iMidiController, bool> res = std::map<int, MidiController*, std::less<int> >::insert(p);
864 return res;
865 }
866
insert(iMidiController ic,const std::pair<int,MidiController * > & p)867 iMidiController MidiControllerList::insert(iMidiController ic, const std::pair<int, MidiController*>& p)
868 {
869 #ifdef _MIDI_CTRL_DEBUG_
870 printf("MidiControllerList::insertAt num:%d\n", p.second->num());
871 #endif
872 iMidiController res = std::map<int, MidiController*, std::less<int> >::insert(ic, p);
873 return res;
874 }
875
erase(iMidiController ictl)876 void MidiControllerList::erase(iMidiController ictl)
877 {
878 #ifdef _MIDI_CTRL_DEBUG_
879 printf("MidiControllerList::erase iMidiController num:%d\n", ictl->second->num());
880 #endif
881 std::map<int, MidiController*, std::less<int> >::erase(ictl);
882 }
883
erase(int num)884 MidiControllerList::size_type MidiControllerList::erase(int num)
885 {
886 #ifdef _MIDI_CTRL_DEBUG_
887 printf("MidiControllerList::erase num:%d\n", num);
888 #endif
889 size_type res = std::map<int, MidiController*, std::less<int> >::erase(num);
890 return res;
891 }
892
erase(iMidiController first,iMidiController last)893 void MidiControllerList::erase(iMidiController first, iMidiController last)
894 {
895 #ifdef _MIDI_CTRL_DEBUG_
896 printf("MidiControllerList::erase range first num:%d second num:%d\n",
897 first->second->num(), last->second->num());
898 #endif
899 std::map<int, MidiController*, std::less<int> >::erase(first, last);
900 }
901
clear()902 void MidiControllerList::clear()
903 {
904 #ifdef _MIDI_CTRL_DEBUG_
905 printf("MidiControllerList::clear\n");
906 #endif
907 std::map<int, MidiController*, std::less<int> >::clear();
908 }
909
910 #endif
911 // =========================================================
912
913 //---------------------------------------------------------
914 // perNoteController
915 // Returns per-note controller if there is one for the given ctl number.
916 // Otherwise returns null.
917 //---------------------------------------------------------
918
perNoteController(int ctl) const919 MidiController* MidiControllerList::perNoteController(int ctl) const
920 {
921 const int n = ctl & 0xff0000;
922 if(((ctl | 0xff) == CTRL_POLYAFTER) ||
923 (n == CTRL_RPN_OFFSET ||
924 n == CTRL_NRPN_OFFSET ||
925 n == CTRL_RPN14_OFFSET ||
926 n == CTRL_NRPN14_OFFSET))
927 {
928 // Does the list have a per-note controller to match the controller number?
929 const_iterator imc = find(ctl | 0xff);
930 if(imc != cend())
931 // Yes, it's a per-note controller. Return a pointer to it.
932 return imc->second;
933 }
934 return nullptr;
935 }
936
findController(int ctl) const937 MidiController* MidiControllerList::findController(int ctl) const
938 {
939 // Find a controller for the verbose ctl number.
940 const_iterator i = find(ctl);
941 if(i != cend())
942 return i->second;
943 // Find a per-note controller for the ctl number.
944 return perNoteController(ctl);
945 }
946
947 //---------------------------------------------------------
948 // searchControllers
949 //---------------------------------------------------------
950
searchControllers(int ctl)951 iMidiController MidiControllerList::searchControllers(int ctl)
952 {
953 const int type = ctl & CTRL_OFFSET_MASK;
954 int n;
955
956 // Looking for Controller7? See if any Controller14 contains the number and should be used instead.
957 if(type == CTRL_7_OFFSET)
958 {
959 const int num = ctl & 0xff;
960 for(iMidiController imc = lower_bound(CTRL_14_OFFSET); imc != end(); ++imc)
961 {
962 n = imc->second->num();
963 // Stop if we went beyond this ctrl14 block.
964 if((n & CTRL_OFFSET_MASK) != CTRL_14_OFFSET)
965 break;
966 if(((n >> 8) & 0xff) == num || (n & 0xff) == num)
967 return imc;
968 }
969 }
970 // Looking for RPN? See if any RPN14 also uses the number and should be used instead.
971 else if (type == CTRL_RPN_OFFSET)
972 {
973 const int num = ctl & 0xffff;
974 for(iMidiController imc = lower_bound(CTRL_RPN14_OFFSET); imc != end(); ++imc)
975 {
976 n = imc->second->num();
977 // Stop if we went beyond this RPN14 block.
978 if((n & CTRL_OFFSET_MASK) != CTRL_RPN14_OFFSET)
979 break;
980 if((n & 0xffff) == num)
981 return imc;
982 }
983 }
984 // Looking for NRPN? See if any NRPN14 also uses the number and should be used instead.
985 else if (type == CTRL_NRPN_OFFSET)
986 {
987 const int num = ctl & 0xffff;
988 for(iMidiController imc = lower_bound(CTRL_NRPN14_OFFSET); imc != end(); ++imc)
989 {
990 n = imc->second->num();
991 // Stop if we went beyond this NRPN14 block.
992 if((n & CTRL_OFFSET_MASK) != CTRL_NRPN14_OFFSET)
993 break;
994 if((n & 0xffff) == num)
995 return imc;
996 }
997 }
998
999 // Looking for any other type? Do a regular find.
1000 return find(ctl);
1001 }
1002
1003 //---------------------------------------------------------
1004 // ctrlAvailable
1005 // Check if either a per-note controller, or else a regular controller already exists.
1006 //---------------------------------------------------------
1007
ctrlAvailable(int find_num,MidiController * ignore_this)1008 bool MidiControllerList::ctrlAvailable(int find_num, MidiController* ignore_this)
1009 {
1010 MusECore::ciMidiController imc;
1011 for(imc = begin(); imc != end(); ++ imc)
1012 {
1013 // Ignore this controller.
1014 if(ignore_this && imc->second == ignore_this)
1015 continue;
1016 int n = imc->second->num();
1017 if(((find_num & 0xff) == 0xff) && ((n | 0xff) == find_num))
1018 break;
1019 if(imc->second->isPerNoteController() && ((find_num | 0xff) == n))
1020 break;
1021 if(find_num == n)
1022 break;
1023 }
1024 return imc == end();
1025 }
1026
1027
1028 } // namespace MusECore
1029