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