1 //=========================================================
2 //  MusE
3 //  Linux Music Editor
4 //  $Id: minstrument.cpp,v 1.10.2.5 2009/03/28 01:46:10 terminator356 Exp $
5 //
6 //  (C) Copyright 2000-2003 Werner Schweer (ws@seh.de)
7 //  (C) Copyright 2016 Tim E. Real (terminator356 on users dot sourceforge dot net)
8 //
9 //  This program is free software; you can redistribute it and/or
10 //  modify it under the terms of the GNU General Public License
11 //  as published by the Free Software Foundation; version 2 of
12 //  the License, or (at your option) any later version.
13 //
14 //  This program is distributed in the hope that it will be useful,
15 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
16 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 //  GNU General Public License for more details.
18 //
19 //  You should have received a copy of the GNU General Public License
20 //  along with this program; if not, write to the Free Software
21 //  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
22 //
23 //=========================================================
24 
25 #include <stdio.h>
26 #include <string.h>
27 
28 #include <QAction>
29 #include <QDir>
30 #include <QFileInfo>
31 #include <QString>
32 #include <QByteArray>
33 #include <QApplication>
34 
35 #include "minstrument.h"
36 #include "mididev.h"
37 #include "midiport.h"
38 #include "audio.h"
39 #include "midi_consts.h"
40 #include "globals.h"
41 #include "midictrl.h"
42 #include "gconfig.h"
43 #include "helper.h"
44 #include "menutitleitem.h"
45 #include "synth.h"
46 #include "icons.h"
47 
48 // Forwards from header:
49 #include "event.h"
50 #include "popupmenu.h"
51 #include "midi_controller.h"
52 #include "mpevent.h"
53 #include "xml.h"
54 
55 #ifdef _USE_INSTRUMENT_OVERRIDES_
56 namespace MusEGlobal {
57   // This list holds instrument drum map overrides read from config.
58   // Whenever an instrument has been loaded it will adopt any corresponding item in this list.
59   // (Instruments are loaded long after config is loaded. So we need this 'holding' list.)
60   MusECore::WorkingDrumMapInstrumentList workingDrumMapInstrumentList;
61 }
62 #endif
63 
64 namespace MusECore {
65 
66 MidiInstrumentList midiInstruments;
67 MidiInstrument* genericMidiInstrument;
68 
69 //---------------------------------------------------------
70 //   string2sysex
71 //   Return -1 if cannot be converted.
72 //---------------------------------------------------------
73 
string2sysex(const QString & s,unsigned char ** data)74 int string2sysex(const QString& s, unsigned char** data)
75       {
76       QByteArray ba = s.toLatin1();
77       const char* src = ba.constData();
78       char buffer[2048];
79       char* dst = buffer;
80 
81       if(src) {
82         while (*src) {
83           while (*src == ' ' || *src == '\n') {
84             ++src;
85           }
86           if(!(*src))
87             break;
88           char* ep;
89           long val = strtol(src, &ep, 16);
90           if (ep == src) {
91             printf("string2sysex: Cannot convert string to sysex %s\n", src);
92             return -1;
93           }
94           src    = ep;
95           // Strip all f0 and f7 (whether accidental or on purpose enclosing etc).
96           if(val == MusECore::ME_SYSEX || val == MusECore::ME_SYSEX_END)
97             continue;
98           *dst++ = val;
99           if (dst - buffer >= 2048) {
100             printf("string2sysex: Hex String too long (2048 bytes limit)\n");
101             return -1;
102           }
103         }
104       }
105 
106       int len = dst - buffer;
107       if(len > 0)
108       {
109         unsigned char* b = new unsigned char[len];
110         memcpy(b, buffer, len);
111         *data = b;
112       }
113       else
114         *data = 0;
115 
116       return len;
117       }
118 
119 //---------------------------------------------------------
120 //   sysex2string
121 //---------------------------------------------------------
122 
sysex2string(int len,unsigned char * data)123 QString sysex2string(int len, unsigned char* data)
124       {
125       QString d;
126       for (int i = 0; i < len; ++i) {
127             if ((i > 0) && ((i % 8)==0)) {
128                   d += QString("\n");
129                   }
130             else if (i)
131                   d += QString(" ");
132             // Strip all f0 and f7 (whether accidental or on purpose enclosing etc).
133             if(data[i] == MusECore::ME_SYSEX || data[i] == MusECore::ME_SYSEX_END)
134               continue;
135             d += QString("%1").arg(data[i], 2, 16, QLatin1Char('0'));
136             }
137       return d;
138       }
139 
140 //---------------------------------------------------------
141 //   readEventList
142 //---------------------------------------------------------
143 
readEventList(Xml & xml,EventList * el,const char * name)144 static void readEventList(Xml& xml, EventList* el, const char* name)
145       {
146       for (;;) {
147             Xml::Token token = xml.parse();
148             const QString& tag = xml.s1();
149             switch (token) {
150                   case Xml::Error:
151                   case Xml::End:
152                         return;
153                   case Xml::TagStart:
154                         if (tag == "event") {
155                               Event e(Note);
156                               e.read(xml);
157                               el->add(e);
158                               }
159                         else
160                               xml.unknown("readEventList");
161                         break;
162                   case Xml::TagEnd:
163                         if (tag == name)
164                               return;
165                   default:
166                         break;
167                   }
168             }
169       }
170 
171 //---------------------------------------------------------
172 //   read
173 //---------------------------------------------------------
174 
175 //---------------------------------------------------------
176 //   loadIDF
177 //---------------------------------------------------------
178 
loadIDF(QFileInfo * fi)179 static void loadIDF(QFileInfo* fi)
180       {
181       FILE* f = fopen(fi->filePath().toLatin1().constData(), "r");
182       if (f == 0)
183             return;
184       if (MusEGlobal::debugMsg)
185             printf("READ IDF %s\n", fi->filePath().toLatin1().constData());
186       Xml xml(f);
187 
188       bool skipmode = true;
189       for (;;) {
190             Xml::Token token = xml.parse();
191             const QString& tag = xml.s1();
192             switch (token) {
193                   case Xml::Error:
194                   case Xml::End:
195                         goto loadIDF_end;
196                   case Xml::TagStart:
197                         if (skipmode && tag == "muse")
198                               skipmode = false;
199                         else if (skipmode)
200                               break;
201                         else if (tag == "MidiInstrument") {
202                               MidiInstrument* i = new MidiInstrument();
203                               i->setFilePath(fi->filePath());
204                               i->read(xml);
205                               // Ignore duplicate named instruments.
206                               iMidiInstrument ii = midiInstruments.begin();
207                               for(; ii != midiInstruments.end(); ++ii)
208                               {
209                                 if((*ii)->iname() == i->iname())
210                                   break;
211                               }
212                               if(ii == midiInstruments.end())
213                               {
214 
215 #ifdef _USE_INSTRUMENT_OVERRIDES_
216                                 // Add in the drum map overrides that were found in config.
217                                 // They can only be added now that the instrument has been loaded.
218                                 ciWorkingDrumMapInstrumentList_t iwdmil =
219                                   MusEGlobal::workingDrumMapInstrumentList.find(i->iname().toStdString());
220                                 if(iwdmil != MusEGlobal::workingDrumMapInstrumentList.end())
221                                 {
222                                   const WorkingDrumMapPatchList& wdmil = iwdmil->second;
223                                   patch_drummap_mapping_list_t* pdml = i->get_patch_drummap_mapping();
224                                   int patch;
225                                   for(ciWorkingDrumMapPatchList_t iwdmpl = wdmil.begin(); iwdmpl != wdmil.end(); ++iwdmpl)
226                                   {
227                                     patch = iwdmpl->first;
228                                     iPatchDrummapMapping_t ipdm = pdml->find(patch, false); // No default.
229                                     if(ipdm != pdml->end())
230                                     {
231                                       patch_drummap_mapping_t& pdm = *ipdm;
232                                       const WorkingDrumMapList& wdml = iwdmpl->second;
233                                       pdm._workingDrumMapList = wdml;
234                                     }
235                                   }
236                                   // TODO: Done with the config override, so erase it? Hm, maybe we might need it later...
237                                   //MusEGlobal::workingDrumMapInstrumentList.erase(iwdmil);
238                                 }
239 #endif
240                                 midiInstruments.push_back(i);
241                               }
242                               else
243                                 delete i;
244                             }
245                         else
246                               xml.unknown("muse");
247                         break;
248                   case Xml::Attribut:
249                         break;
250                   case Xml::TagEnd:
251                         if (!skipmode && tag == "muse") {
252                               goto loadIDF_end;
253                               }
254                   default:
255                         break;
256                   }
257             }
258 
259 loadIDF_end:
260       fclose(f);
261       }
262 
263 //---------------------------------------------------------
264 //   initMidiInstruments
265 //---------------------------------------------------------
266 
initMidiInstruments()267 void initMidiInstruments()
268       {
269       genericMidiInstrument = new MidiInstrument(QWidget::tr("Generic midi"));
270       midiInstruments.push_back(genericMidiInstrument);
271 
272       // Initialize with a default drum map on default channel. Patch is default 0xffffff. GM-1 does not specify a drum patch number.
273       ChannelDrumMappingList* cdml = genericMidiInstrument->getChannelDrumMapping();
274       cdml->add(-1, patch_drummap_mapping_list_t());
275 
276 #ifdef _USE_INSTRUMENT_OVERRIDES_
277       // Add in the drum map overrides that were found in config.
278       // They can only be added now that the instrument has been created.
279       ciWorkingDrumMapInstrumentList_t iwdmil =
280         MusEGlobal::workingDrumMapInstrumentList.find(genericMidiInstrument->iname().toStdString());
281       if(iwdmil != MusEGlobal::workingDrumMapInstrumentList.end())
282       {
283         const WorkingDrumMapPatchList& wdmil = iwdmil->second;
284         int patch;
285         for(ciWorkingDrumMapPatchList_t iwdmpl = wdmil.begin(); iwdmpl != wdmil.end(); ++iwdmpl)
286         {
287           patch = iwdmpl->first;
288           iPatchDrummapMapping_t ipdm = pdml->find(patch, false); // No default.
289           if(ipdm != pdml->end())
290           {
291             patch_drummap_mapping_t& pdm = *ipdm;
292             const WorkingDrumMapList& wdml = iwdmpl->second;
293             pdm._workingDrumMapList = wdml;
294           }
295         }
296         // TODO: Done with the config override, so erase it? Hm, maybe we might need it later...
297         //MusEGlobal::workingDrumMapInstrumentList.erase(iwdmil);
298       }
299 #endif
300 
301       if (MusEGlobal::debugMsg)
302         printf("load user instrument definitions from <%s>\n", MusEGlobal::museUserInstruments.toLatin1().constData());
303       QDir usrInstrumentsDir(MusEGlobal::museUserInstruments, QString("*.idf"));
304       if (usrInstrumentsDir.exists()) {
305             QFileInfoList list = usrInstrumentsDir.entryInfoList();
306             QFileInfoList::iterator it=list.begin(); // ddskrjo
307             while(it != list.end()) { // ddskrjo
308                   loadIDF(&*it);
309                   ++it;
310                   }
311             }
312 
313       if (MusEGlobal::debugMsg)
314         printf("load instrument definitions from <%s>\n", MusEGlobal::museInstruments.toLatin1().constData());
315       QDir instrumentsDir(MusEGlobal::museInstruments, QString("*.idf"));
316       if (instrumentsDir.exists()) {
317             QFileInfoList list = instrumentsDir.entryInfoList();
318             QFileInfoList::iterator it=list.begin(); // ddskrjo
319             while(it!=list.end()) {
320                   loadIDF(&*it);
321                   ++it;
322                   }
323             }
324       else
325         printf("Instrument directory not found: %s\n", MusEGlobal::museInstruments.toLatin1().constData());
326 
327       }
328 
329 //---------------------------------------------------------
330 //   registerMidiInstrument
331 //---------------------------------------------------------
332 
registerMidiInstrument(const QString & name)333 MidiInstrument* registerMidiInstrument(const QString& name)
334       {
335       for (iMidiInstrument i = midiInstruments.begin();
336          i != midiInstruments.end(); ++i) {
337             if ((*i)->iname() == name)
338                   return *i;
339             }
340       return genericMidiInstrument;
341       }
342 
343 //---------------------------------------------------------
344 //   removeMidiInstrument
345 //---------------------------------------------------------
346 
removeMidiInstrument(const QString & name)347 void removeMidiInstrument(const QString& name)
348       {
349       for (iMidiInstrument i = midiInstruments.begin();
350          i != midiInstruments.end(); ++i) {
351             if ((*i)->iname() == name) {
352                   midiInstruments.erase(i);
353                   return;
354                   }
355             }
356       }
357 
removeMidiInstrument(const MidiInstrument * instr)358 void removeMidiInstrument(const MidiInstrument* instr)
359       {
360       for (iMidiInstrument i = midiInstruments.begin();
361          i != midiInstruments.end(); ++i) {
362             if (*i == instr) {
363                   midiInstruments.erase(i);
364                   return;
365                   }
366             }
367       }
368 
369 //---------------------------------------------------------
370 //   findMidiInstrument
371 //---------------------------------------------------------
372 
find(const MidiInstrument * instr)373 iMidiInstrument MidiInstrumentList::find(const MidiInstrument* instr)
374       {
375       for (iMidiInstrument i = begin();
376          i != end(); ++i) {
377             if (*i == instr) {
378                   return i;
379                   }
380             }
381       return end();
382       }
383 
384 #ifdef _USE_INSTRUMENT_OVERRIDES_
writeDrummapOverrides(int level,Xml & xml) const385 void MidiInstrumentList::writeDrummapOverrides(int level, Xml& xml) const
386 {
387   MidiInstrument* mi;
388   for(ciMidiInstrument imi = begin(); imi != end(); ++imi)
389   {
390     mi = *imi;
391     mi->writeDrummapOverrides(level, xml);
392   }
393 }
394 #endif
395 
396 //---------------------------------------------------------
397 //   MidiInstrument
398 //---------------------------------------------------------
399 
init()400 void MidiInstrument::init()
401       {
402       _noteOffMode = NoteOffAll; // By default, use note offs.
403       _tmpMidiStateVersion = 1; // Assume old version. readMidiState will overwrite anyway.
404       _initScript = 0;
405       _waitForLSB = true;
406       _midiInit  = new EventList();
407       _midiReset = new EventList();
408       _midiState = new EventList();
409       _controller = new MidiControllerList;
410 
411       // add some default controller to controller list
412       // this controllers are always available for all instruments
413       //
414       MidiController* prog = new MidiController("Program", CTRL_PROGRAM, 0, 0xffffff, 0, 0);
415       _controller->add(prog);
416       _dirty = false;
417 
418       }
419 
MidiInstrument()420 MidiInstrument::MidiInstrument()
421       {
422       init();
423       }
424 
425 //---------------------------------------------------------
426 //   MidiInstrument
427 //---------------------------------------------------------
428 
MidiInstrument(const QString & txt)429 MidiInstrument::MidiInstrument(const QString& txt)
430       {
431       _name = txt;
432       init();
433       }
434 
435 //---------------------------------------------------------
436 //   MidiInstrument
437 //---------------------------------------------------------
438 
~MidiInstrument()439 MidiInstrument::~MidiInstrument()
440       {
441       for (ciPatchGroup g = pg.begin(); g != pg.end(); ++g)
442       {
443         PatchGroup* pgp = *g;
444         const PatchList& pl = pgp->patches;
445         for (ciPatch p = pl.begin(); p != pl.end(); ++p)
446         {
447           delete *p;
448         }
449         delete pgp;
450       }
451 
452 
453       delete _midiInit;
454       delete _midiReset;
455       delete _midiState;
456       for(iMidiController i = _controller->begin(); i != _controller->end(); ++i)
457           delete i->second;
458       delete _controller;
459 
460       if (_initScript)
461             delete _initScript;
462 
463       if(!_sysex.isEmpty())
464       {
465         int j = _sysex.size();
466         for(int i = 0; i < j; ++i)
467           delete _sysex.at(i);
468       }
469 
470       _channelDrumMapping.clear();
471       }
472 
473 //---------------------------------------------------------
474 //   assign
475 //---------------------------------------------------------
476 
assign(const MidiInstrument & ins)477 MidiInstrument& MidiInstrument::assign(const MidiInstrument& ins)
478 {
479   //---------------------------------------------------------
480   // TODO: Copy the _initScript (if and when it is ever used)
481   //---------------------------------------------------------
482 
483   for(iMidiController i = _controller->begin(); i != _controller->end(); ++i)
484       delete i->second;
485 
486   _controller->clr();
487   _waitForLSB = ins._waitForLSB;
488   _noteOffMode = ins._noteOffMode;
489 
490   // Assignment
491   for(ciMidiController i = ins._controller->begin(); i != ins._controller->end(); ++i)
492   {
493     MidiController* mc = i->second;
494     _controller->add(new MidiController(*mc));
495   }
496 
497   if(!_sysex.isEmpty())
498   {
499     int j = _sysex.size();
500     for(int i = 0; i < j; ++i)
501       delete _sysex.at(i);
502     _sysex.clear();
503   }
504   if(!ins.sysex().isEmpty())
505   {
506     int j = ins.sysex().size();
507     for(int i = 0; i < j; ++i)
508       _sysex.append(new MusECore::SysEx(*(ins.sysex().at(i))));
509   }
510 
511   *(_midiInit) = *(ins._midiInit);
512   *(_midiReset) = *(ins._midiReset);
513   *(_midiState) = *(ins._midiState);
514 
515   for (ciPatchGroup g = pg.begin(); g != pg.end(); ++g)
516   {
517     PatchGroup* pgp = *g;
518     const PatchList& pl = pgp->patches;
519     for (ciPatch p = pl.begin(); p != pl.end(); ++p)
520     {
521       delete *p;
522     }
523 
524     delete pgp;
525   }
526   pg.clear();
527 
528   // Assignment
529   for(ciPatchGroup g = ins.pg.begin(); g != ins.pg.end(); ++g)
530   {
531     PatchGroup* pgp = *g;
532     const PatchList& pl = pgp->patches;
533     PatchGroup* npg = new PatchGroup;
534     npg->name = pgp->name;
535     pg.push_back(npg);
536     for (ciPatch p = pl.begin(); p != pl.end(); ++p)
537     {
538       Patch* pp = *p;
539       Patch* np = new Patch;
540       //np->typ = pp->typ;
541       np->hbank = pp->hbank;
542       np->lbank = pp->lbank;
543       np->program = pp->program;
544       np->name = pp->name;
545       np->drum = pp->drum;
546       npg->patches.push_back(np);
547     }
548   }
549 
550   _name = ins._name;
551   _filePath = ins._filePath;
552 
553   _channelDrumMapping = ins._channelDrumMapping;
554 
555   // Hmm, dirty, yes? But init sets it to false... DELETETHIS
556   //_dirty = ins._dirty;
557   //_dirty = false;
558   //_dirty = true;
559 
560   return *this;
561 }
562 
563 //---------------------------------------------------------
564 //   midiType
565 //---------------------------------------------------------
566 
midiType() const567 MType MidiInstrument::midiType() const
568 {
569   if(_name == "GM")
570     return MT_GM;
571   if(_name == "GM2")
572     return MT_GM2;
573   if(_name == "GS")
574     return MT_GS;
575   if(_name == "XG")
576     return MT_XG;
577   return MT_UNKNOWN;
578 }
579 
580 //---------------------------------------------------------
581 //   reset
582 //    send note off to all channels
583 //   To be called by audio thread only.
584 //---------------------------------------------------------
585 
reset(int portNo)586 void MidiInstrument::reset(int portNo)
587 {
588       MusECore::MidiPort* port = &MusEGlobal::midiPorts[portNo];
589       if(port->device() == 0)
590         return;
591 
592       MusECore::MidiPlayEvent ev;
593       ev.setType(ME_NOTEOFF);
594       ev.setPort(portNo);
595       ev.setTime(0);  // Immediate processing. TODO: Use curFrame?
596       ev.setB(64);
597 
598       for (int chan = 0; chan < MusECore::MUSE_MIDI_CHANNELS; ++chan)
599       {
600             ev.setChannel(chan);
601             for (int pitch = 0; pitch < 128; ++pitch)
602             {
603                   ev.setA(pitch);
604                   port->device()->putEvent(ev, MidiDevice::NotLate);
605             }
606       }
607 }
608 
609 //---------------------------------------------------------
610 //   readPatchGroup
611 //---------------------------------------------------------
612 
read(Xml & xml)613 void PatchGroup::read(Xml& xml)
614       {
615       for (;;) {
616             Xml::Token token = xml.parse();
617             const QString& tag = xml.s1();
618             switch (token) {
619                   case Xml::Error:
620                   case Xml::End:
621                         return;
622                   case Xml::TagStart:
623                         if (tag == "Patch") {
624                               Patch* patch = new Patch;
625                               patch->read(xml);
626                               patches.push_back(patch);
627                               }
628                         else
629                               xml.unknown("PatchGroup");
630                         break;
631                   case Xml::Attribut:
632                         if (tag == "name")
633                               name = xml.s2();
634                         break;
635                   case Xml::TagEnd:
636                         if (tag == "PatchGroup")
637                               return;
638                   default:
639                         break;
640                   }
641             }
642       }
643 
644 //---------------------------------------------------------
645 //   read
646 //---------------------------------------------------------
647 
read(Xml & xml)648 void Patch::read(Xml& xml)
649       {
650       hbank = -1;
651       lbank = -1;
652       program  = -1;
653       drum  = false;
654       for (;;) {
655             Xml::Token token = xml.parse();
656             const QString& tag = xml.s1();
657             switch (token) {
658                   case Xml::Error:
659                   case Xml::End:
660                         return;
661                   case Xml::TagStart:
662                         xml.unknown("Patch");
663                         break;
664                   case Xml::Attribut:
665                         if (tag == "name")
666                               name = xml.s2();
667                         else if (tag == "mode")  // Obsolete
668                         {
669                               xml.s2().toInt();
670                         }
671                         else if (tag == "hbank")
672                               hbank = xml.s2().toInt();
673                         else if (tag == "lbank")
674                               lbank = xml.s2().toInt();
675                         else if (tag == "prog")
676                               program = xml.s2().toInt();
677                         else if (tag == "drum")
678                               drum = xml.s2().toInt();
679                         break;
680                   case Xml::TagEnd:
681                         if (tag == "Patch")
682                               return;
683                   default:
684                         break;
685                   }
686             }
687       }
688 
689 //---------------------------------------------------------
690 //   write
691 //---------------------------------------------------------
692 
write(int level,Xml & xml)693 void Patch::write(int level, Xml& xml)
694       {
695             xml.nput(level, "<Patch name=\"%s\"", Xml::xmlString(name).toLatin1().constData());
696 
697             if(hbank != -1)
698               xml.nput(" hbank=\"%d\"", hbank);
699 
700             if(lbank != -1)
701               xml.nput(" lbank=\"%d\"", lbank);
702 
703             if(program != -1)
704               xml.nput(" prog=\"%d\"", program);
705 
706             if(drum)
707               xml.nput(" drum=\"%d\"", int(drum));
708             xml.put(" />");
709       }
710 
find(int patch,bool drum,bool includeDefault)711 iPatch PatchList::find(int patch, bool drum, bool includeDefault)
712 {
713   int pnum;
714   Patch* p;
715   iPatch ip_default = end();
716   for(iPatch ip = begin(); ip != end(); ++ip)
717   {
718     p = *ip;
719     pnum = p->patch();
720     // Look for an exact match above all else. The given patch must be valid.
721     if(patch != CTRL_VAL_UNKNOWN && pnum == patch && p->drum == drum)
722       return ip;
723     // If no exact match is found we'll take a default if found (all three pr, hb, lb = don't care).
724     if(includeDefault && p->dontCare() && p->drum == drum && ip_default == end())
725       ip_default = ip;
726   }
727   return ip_default;
728 }
729 
find(int patch,bool drum,bool includeDefault) const730 ciPatch PatchList::find(int patch, bool drum, bool includeDefault) const
731 {
732   int pnum;
733   const Patch* p;
734   ciPatch ip_default = end();
735   for(ciPatch ip = begin(); ip != end(); ++ip)
736   {
737     p = *ip;
738     pnum = p->patch();
739     // Look for an exact match above all else. The given patch must be valid.
740     if(patch != CTRL_VAL_UNKNOWN && pnum == patch && p->drum == drum)
741       return ip;
742     // If no exact match is found we'll take a default if found (all three pr, hb, lb = don't care).
743     if(includeDefault && p->dontCare() && p->drum == drum && ip_default == end())
744       ip_default = ip;
745   }
746   return ip_default;
747 }
748 
findPatch(int patch,bool drum,bool includeDefault)749 Patch* PatchGroupList::findPatch(int patch, bool drum, bool includeDefault)
750 {
751   for(iPatchGroup ipg = begin(); ipg != end(); ++ipg)
752   {
753     PatchGroup* pg = *ipg;
754     iPatch ip = pg->patches.find(patch, drum, includeDefault);
755     if(ip != pg->patches.end())
756       return *ip;
757   }
758   return 0;
759 }
760 
findPatch(int patch,bool drum,bool includeDefault) const761 Patch* PatchGroupList::findPatch(int patch, bool drum, bool includeDefault) const
762 {
763   for(ciPatchGroup ipg = begin(); ipg != end(); ++ipg)
764   {
765     const PatchGroup* pg = *ipg;
766     ciPatch ip = pg->patches.find(patch, drum, includeDefault);
767     if(ip != pg->patches.end())
768       return *ip;
769   }
770   return 0;
771 }
772 
773 
774 //---------------------------------------------------------
775 //   SysEx
776 //---------------------------------------------------------
777 
SysEx()778 SysEx::SysEx()
779 {
780   dataLen = 0;
781   data = 0;
782 }
783 
SysEx(const SysEx & src)784 SysEx::SysEx(const SysEx& src)
785 {
786   name    = src.name;
787   comment = src.comment;
788   dataLen = src.dataLen;
789   data = 0;
790   if(dataLen != 0 && src.data)
791   {
792     data = new unsigned char[dataLen];
793     memcpy(data, src.data, dataLen);
794   }
795 }
796 
~SysEx()797 SysEx::~SysEx()
798 {
799   if(dataLen != 0 && data)
800     delete[] data;
801 }
802 
read(Xml & xml)803 bool SysEx::read(Xml& xml)
804       {
805       for (;;) {
806             Xml::Token token = xml.parse();
807             const QString& tag = xml.s1();
808             switch (token) {
809                   case Xml::Error:
810                   case Xml::End:
811                         return false;
812                   case Xml::TagStart:
813                         if (tag == "comment")
814                               comment = xml.parse1();
815                         else if (tag == "data")
816                         {
817                               unsigned char*d;
818                               int len = string2sysex(xml.parse1(), &d);
819                               // Was the conversion successful, even if empty?
820                               if(len != -1)
821                               {
822                                 // Delete existing.
823                                 if(dataLen != 0 && data)
824                                   delete[] data;
825                                 dataLen = len;
826                                 data = d;
827                               }
828                         }
829                         else
830                               xml.unknown("SysEx");
831                         break;
832                   case Xml::Attribut:
833                         if (tag == "name")
834                               name = xml.s2();
835                         break;
836                   case Xml::TagEnd:
837                         if (tag == "SysEx")
838                         {
839                           return !name.isEmpty();
840                         }
841                   default:
842                         break;
843                   }
844             }
845 
846       return false;
847       }
848 
write(int level,Xml & xml)849 void SysEx::write(int level, Xml& xml)
850       {
851             xml.nput(level, "<SysEx name=\"%s\">\n", Xml::xmlString(name).toLatin1().constData());
852 
853             level++;
854             if(!comment.isEmpty())
855               xml.strTag(level, "comment", comment.toLatin1().constData());
856             if(dataLen > 0 && data)
857               xml.strTag(level, "data", sysex2string(dataLen, data));
858 
859             xml.etag(level, "SysEx");
860       }
861 
862 //---------------------------------------------------------
863 //   readMidiState
864 //---------------------------------------------------------
865 
readMidiState(Xml & xml)866 void MidiInstrument::readMidiState(Xml& xml)
867 {
868   // A kludge to support old midistates by wrapping them in the proper header.
869   _tmpMidiStateVersion = 1;    // Assume old (unmarked) first version 1.
870   for (;;)
871   {
872     Xml::Token token = xml.parse();
873     const QString tag = xml.s1();
874     switch (token)
875     {
876           case Xml::Error:
877           case Xml::End:
878                 return;
879           case Xml::TagStart:
880                 if (tag == "event")
881                 {
882                   Event e(Note);
883                   e.read(xml);
884                   _midiState->add(e);
885                 }
886                 else
887                 xml.unknown("midistate");
888                 break;
889           case Xml::Attribut:
890                 if(tag == "version")
891                   _tmpMidiStateVersion = xml.s2().toInt();
892                 else
893                   xml.unknown("MidiInstrument");
894                 break;
895           case Xml::TagEnd:
896                 if(tag == "midistate")
897                   return;
898           default:
899                 break;
900     }
901   }
902 }
903 
readDrummaps(Xml & xml)904 void MidiInstrument::readDrummaps(Xml& xml)
905 {
906   //_channelDrumMapping.clear(); // ???
907   const QString start_tag = xml.s1();
908   for (;;)
909   {
910     Xml::Token token = xml.parse();
911     const QString& tag = xml.s1();
912     switch (token)
913     {
914       case Xml::Error:
915       case Xml::End:
916         return;
917 
918       case Xml::TagStart:
919         if (tag == "drumMapChannel")
920           _channelDrumMapping.read(xml);
921         else if (tag == "entry")
922         {
923           patch_drummap_mapping_list_t pdml;
924           pdml.read(xml);
925           if(!pdml.empty())
926             _channelDrumMapping.add(-1, pdml); // Add to the default channel.
927         }
928         else
929           xml.unknown("MidiInstrument::readDrummaps");
930         break;
931 
932       case Xml::TagEnd:
933         if (tag == start_tag)
934           return;
935 
936       default:
937         break;
938     }
939   }
940 }
941 
writeDrummaps(int level,Xml & xml) const942 void MidiInstrument::writeDrummaps(int level, Xml& xml) const
943 {
944   xml.tag(level++, "Drummaps");
945 
946   _channelDrumMapping.write(level, xml);
947 
948   xml.etag(--level, "Drummaps");
949 }
950 
951 //---------------------------------------------------------
952 //   read
953 //---------------------------------------------------------
954 
read(Xml & xml)955 void MidiInstrument::read(Xml& xml)
956       {
957       for (;;) {
958             Xml::Token token = xml.parse();
959             const QString& tag = xml.s1();
960             switch (token) {
961                   case Xml::Error:
962                   case Xml::End:
963                         return;
964                   case Xml::TagStart:
965                         if (tag == "Patch") {
966                               Patch* patch = new Patch;
967                               patch->read(xml);
968                               if (pg.empty()) {
969                                     PatchGroup* p = new PatchGroup;
970                                     p->patches.push_back(patch);
971                                     pg.push_back(p);
972                                     }
973                               else
974                                     pg[0]->patches.push_back(patch);
975                               }
976                         else if (tag == "PatchGroup") {
977                               PatchGroup* p = new PatchGroup;
978                               p->read(xml);
979                               pg.push_back(p);
980                               }
981                         else if (tag == "Controller") {
982                               MidiController* mc = new MidiController();
983                               mc->read(xml);
984                               //
985                               // HACK: make predefined "Program" controller overloadable
986                               //
987                               if (mc->name() == "Program") {
988                                     for (iMidiController i = _controller->begin(); i != _controller->end(); ++i) {
989                                           if (i->second->name() == mc->name()) {
990                                                 delete i->second;
991                                                 _controller->del(i);
992                                                 break;
993                                                 }
994                                           }
995                                     }
996 
997                               _controller->add(mc);
998                               }
999                         else if (tag == "Drummaps") {
1000                               readDrummaps(xml);
1001                               }
1002                         else if (tag == "Init")
1003                               readEventList(xml, _midiInit, "Init");
1004                         else if (tag == "Reset")
1005                               readEventList(xml, _midiReset, "Reset");
1006                         else if (tag == "State")
1007                               readEventList(xml, _midiState, "State");
1008                         else if (tag == "InitScript") {
1009                               if (_initScript)
1010                                     delete _initScript;
1011                               QByteArray ba = xml.parse1().toLatin1();
1012                               const char* istr = ba.constData();
1013                               int len = ba.length() +1;
1014                               if (len > 1) {
1015                                     _initScript = new char[len];
1016                                     memcpy(_initScript, istr, len);
1017                                     }
1018                               }
1019                         else if (tag == "SysEx") {
1020                               SysEx* se = new SysEx;
1021                               if(!se->read(xml))
1022                               {
1023                                 delete se;
1024                                 printf("MidiInstrument::read():SysEx: reading sysex failed\n");
1025                               }
1026                               else
1027                                 _sysex.append(se);
1028                               }
1029                         else
1030                               xml.unknown("MidiInstrument");
1031                         break;
1032                   case Xml::Attribut:
1033                         if (tag == "name")
1034                               setIName(xml.s2());
1035                         else if(tag == "nullparam") { } // Obsolete.
1036                         else if(tag == "NoteOffMode")
1037                               _noteOffMode = (NoteOffMode)xml.s2().toInt(); // Default is NoteOffAll.
1038                         break;
1039                   case Xml::TagEnd:
1040                         if (tag == "MidiInstrument")
1041                               return;
1042                   default:
1043                         break;
1044                   }
1045             }
1046       }
1047 
1048 //---------------------------------------------------------
1049 //   write
1050 //---------------------------------------------------------
1051 
write(int level,Xml & xml)1052 void MidiInstrument::write(int level, Xml& xml)
1053       {
1054       xml.header();
1055       xml.tag(level, "muse version=\"1.0\"");
1056       level++;
1057       xml.nput(level, "<MidiInstrument name=\"%s\"", Xml::xmlString(iname()).toLatin1().constData());
1058 
1059       if(noteOffMode() != NoteOffAll) // Default is NoteOffAll.
1060         xml.nput(" NoteOffMode=\"%d\"", noteOffMode());
1061       xml.put(">");
1062 
1063       level++;
1064       for (ciPatchGroup g = pg.begin(); g != pg.end(); ++g) {
1065             PatchGroup* pgp = *g;
1066             const PatchList& pl = pgp->patches;
1067             xml.tag(level, "PatchGroup name=\"%s\"", Xml::xmlString(pgp->name).toLatin1().constData());
1068             level++;
1069             for (ciPatch p = pl.begin(); p != pl.end(); ++p)
1070                   (*p)->write(level, xml);
1071             level--;
1072             xml.etag(level, "PatchGroup");
1073             }
1074       for (iMidiController ic = _controller->begin(); ic != _controller->end(); ++ic)
1075             ic->second->write(level, xml);
1076       if(!_sysex.isEmpty())
1077       {
1078         int j = _sysex.size();
1079         for(int i = 0; i < j; ++i)
1080           _sysex.at(i)->write(level, xml);
1081       }
1082 
1083       xml.tag(level++, "Init");
1084       for(ciEvent ev=_midiInit->begin(); ev != _midiInit->end(); ++ev)
1085         ev->second.write(level, xml, MusECore::Pos(0, true));
1086       xml.etag(--level, "Init");
1087 
1088       // -------------
1089       // TODO: What about _midiReset, _midiState, and _initScript ?
1090       // -------------
1091 
1092       writeDrummaps(level, xml);
1093 
1094       level--;
1095       xml.etag(level, "MidiInstrument");
1096       level--;
1097       xml.etag(level, "muse");
1098       }
1099 
1100 #ifdef _USE_INSTRUMENT_OVERRIDES_
writeDrummapOverrides(int level,Xml & xml) const1101 void MidiInstrument::writeDrummapOverrides(int level, Xml& xml) const
1102 {
1103   for(ciPatchDrummapMapping_t ipdm = patch_drummap_mapping.begin(); ipdm != patch_drummap_mapping.end(); ++ipdm)
1104   {
1105     if(!(*ipdm)._workingDrumMapList.empty())
1106     {
1107       xml.tag(level++, "drummapOverrides instrument=\"%s\"", Xml::xmlString(iname()).toLatin1().constData());
1108       patch_drummap_mapping.writeDrummapOverrides(level, xml);
1109       xml.etag(--level, "drummapOverrides");
1110       break;
1111     }
1112   }
1113 }
1114 #endif
1115 
1116 //---------------------------------------------------------
1117 //   readMidnamDocument
1118 //---------------------------------------------------------
1119 
1120 #ifdef MIDNAM_SUPPORT
readMidnamDocument(Xml & xml)1121 bool MidiInstrument::readMidnamDocument(Xml& xml)
1122 {
1123   return _midnamDocument.read(xml);
1124 }
1125 #endif
1126 
get_patch_drummap_mapping(int channel,bool includeDefault)1127 patch_drummap_mapping_list_t* MidiInstrument::get_patch_drummap_mapping(int channel, bool includeDefault)
1128 {
1129   patch_drummap_mapping_list_t* pdml = _channelDrumMapping.find(channel, includeDefault);
1130   if(!pdml)
1131     // Not found? Search the global mapping list.
1132     return genericMidiInstrument->getChannelDrumMapping()->find(channel, includeDefault);
1133   return pdml;
1134 }
1135 
1136 //---------------------------------------------------------
1137 //   populateInstrPopup  (static)
1138 //---------------------------------------------------------
1139 
populateInstrPopup(MusEGui::PopupMenu * menu,int port,bool show_synths)1140 void MidiInstrument::populateInstrPopup(MusEGui::PopupMenu* menu, int port, bool show_synths)
1141       {
1142       menu->clear();
1143 
1144       if(port < 0 || port >= MIDI_PORTS)
1145         return;
1146 
1147       const MidiPort* mp = &MusEGlobal::midiPorts[port];
1148       const MidiDevice* md = mp->device();
1149 
1150       const MidiInstrument* dev_curr_instr = mp->instrument();
1151       const SynthI* dev_synth = nullptr;
1152       const MidiInstrument* dev_synth_instr = nullptr;
1153       QAction* act;
1154 
1155       act = menu->addAction(*MusEGui::editInstrumentSVGIcon, QWidget::tr("Edit Instrument..."));
1156       act->setData(100);
1157       menu->addSeparator();
1158 
1159       menu->addAction(new MusEGui::MenuTitleItem(QObject::tr("Instruments"), menu));
1160       menu->addSeparator();
1161 
1162       if(md && md->isSynti())
1163       {
1164         dev_synth = static_cast<const SynthI*>(md);
1165         dev_synth_instr = static_cast<const MidiInstrument*>(dev_synth);
1166       }
1167 
1168       if(dev_synth_instr)
1169       {
1170         menu->addAction(new MusEGui::MenuTitleItem(QObject::tr("Current device"), menu));
1171         act = menu->addAction(dev_synth_instr->iname());
1172         act->setCheckable(true);
1173         if(dev_synth_instr == dev_curr_instr)
1174           act->setChecked(true);
1175       }
1176 
1177       if(!MusECore::midiInstruments.empty())
1178       {
1179         bool has_synths = false;
1180         for (MusECore::ciMidiInstrument i = MusECore::midiInstruments.cbegin(); i
1181             != MusECore::midiInstruments.cend(); ++i)
1182             {
1183               if(show_synths && (*i)->isSynti() && (*i) != dev_synth_instr)
1184               {
1185                 has_synths = true;
1186                 break;
1187               }
1188             }
1189 
1190         if(has_synths)
1191         {
1192           if(dev_synth_instr)
1193             menu->addAction(new MusEGui::MenuTitleItem(QObject::tr("Others"), menu));
1194 
1195           MusEGui::PopupMenu* instr_menu = new MusEGui::PopupMenu(menu, false);
1196           instr_menu->setTitle(QObject::tr("Files"));
1197           for (MusECore::ciMidiInstrument i = MusECore::midiInstruments.cbegin(); i
1198               != MusECore::midiInstruments.cend(); ++i)
1199               {
1200                 if(!(*i)->isSynti())
1201                 {
1202                   act = instr_menu->addAction((*i)->iname());
1203                   act->setCheckable(true);
1204                   if((*i) == dev_curr_instr)
1205                     act->setChecked(true);
1206                 }
1207               }
1208           menu->addMenu(instr_menu);
1209 
1210           MusEGui::PopupMenu* synth_submenu = new MusEGui::PopupMenu(menu, false);
1211           synth_submenu->setTitle(QObject::tr("Synthesizers"));
1212           for (MusECore::ciMidiInstrument i = MusECore::midiInstruments.cbegin(); i
1213               != MusECore::midiInstruments.cend(); ++i)
1214               {
1215                 if((*i)->isSynti() && (*i) != dev_synth_instr)
1216                 {
1217                   act = synth_submenu->addAction((*i)->iname());
1218                   act->setCheckable(true);
1219                   if((*i) == dev_curr_instr)
1220                     act->setChecked(true);
1221                 }
1222               }
1223           menu->addMenu(synth_submenu);
1224         }
1225         else
1226         {
1227           menu->addAction(new MusEGui::MenuTitleItem(QObject::tr("Files"), menu));
1228 
1229           for (MusECore::iMidiInstrument i = MusECore::midiInstruments.begin(); i
1230               != MusECore::midiInstruments.end(); ++i)
1231               {
1232                 if(!(*i)->isSynti())
1233                 {
1234                   act = menu->addAction((*i)->iname());
1235                   act->setCheckable(true);
1236                   if((*i) == dev_curr_instr)
1237                     act->setChecked(true);
1238                 }
1239               }
1240         }
1241       }
1242     }
1243 
1244 //---------------------------------------------------------
1245 //   populatePatchPopup
1246 //---------------------------------------------------------
1247 
populatePatchPopup(MusEGui::PopupMenu * menu,int,bool drum)1248 void MidiInstrument::populatePatchPopup(MusEGui::PopupMenu* menu, int /*chan*/, bool drum)
1249       {
1250       menu->clear();
1251       //int mask = 7;
1252 
1253       if (pg.size() > 1) {
1254             for (ciPatchGroup i = pg.begin(); i != pg.end(); ++i) {
1255                   PatchGroup* pgp = *i;
1256                   MusEGui::PopupMenu* pm = 0;
1257                   const PatchList& pl = pgp->patches;
1258                   for (ciPatch ipl = pl.begin(); ipl != pl.end(); ++ipl) {
1259                         const Patch* mp = *ipl;
1260                         if (//(mp->typ & mask) &&
1261                             (mp->drum == drum)) {
1262                               if(!pm) {
1263                                 pm = new MusEGui::PopupMenu(pgp->name, menu, menu->stayOpen());  // Use the parent stayOpen here.
1264                                 menu->addMenu(pm);
1265                                 pm->setFont(qApp->font());
1266                               }
1267                               const int hb = mp->hbank & 0xff;
1268                               const int lb = mp->lbank & 0xff;
1269                               const int pr = mp->program & 0xff;
1270                               const int id = (hb << 16) | (lb << 8) | pr;
1271                               const bool vhb = hb != 0xff;
1272                               const bool vlb = lb != 0xff;
1273                               const bool vpr = pr != 0xff;
1274                               QString astr;
1275                               if(vhb || vlb || vpr) {
1276                                 if(vhb)
1277                                   astr += QString::number(hb + 1) + QString(":");
1278                                 if(vlb)
1279                                   astr += QString::number(lb + 1) + QString(":");
1280                                 else if(vhb)
1281                                   astr += QString("--:");
1282                                 if(vpr)
1283                                   astr += QString::number(pr + 1);
1284                                 else if(vhb && vlb)
1285                                   astr += QString("--");
1286                                 astr += QString(" ");
1287                               }
1288                               astr += mp->name;
1289                               QAction* act = pm->addAction(astr);
1290                               act->setData(id);
1291                             }
1292                         }
1293                   }
1294             }
1295       else if (pg.size() == 1 ){
1296             // no groups
1297             const PatchList& pl = pg.front()->patches;
1298             for (ciPatch ipl = pl.begin(); ipl != pl.end(); ++ipl) {
1299                   const Patch* mp = *ipl;
1300                   //if (mp->typ & mask) {
1301                         const int hb = mp->hbank & 0xff;
1302                         const int lb = mp->lbank & 0xff;
1303                         const int pr = mp->program & 0xff;
1304                         const int id = (hb << 16) | (lb << 8) | pr;
1305                         const bool vhb = hb != 0xff;
1306                         const bool vlb = lb != 0xff;
1307                         const bool vpr = pr != 0xff;
1308                         QString astr;
1309                         if(vhb || vlb || vpr) {
1310                           if(vhb)
1311                             astr += QString::number(hb + 1) + QString(":");
1312                           if(vlb)
1313                             astr += QString::number(lb + 1) + QString(":");
1314                           else if(vhb)
1315                             astr += QString("--:");
1316                           if(vpr)
1317                             astr += QString::number(pr + 1);
1318                           else if(vhb && vlb)
1319                             astr += QString("--");
1320                           astr += QString(" ");
1321                         }
1322                         astr += mp->name;
1323                         QAction* act = menu->addAction(astr);
1324                         act->setData(id);
1325                         //}
1326                   }
1327             }
1328 
1329     }
1330 
getMapItem(int channel,int patch,int index,DrumMap & dest_map,int overrideType) const1331 void MidiInstrument::getMapItem(int channel, int patch, int index, DrumMap& dest_map, int
1332 #ifdef _USE_INSTRUMENT_OVERRIDES_
1333 overrideType
1334 #endif
1335 ) const
1336 {
1337   const patch_drummap_mapping_list_t* pdml = _channelDrumMapping.find(channel, true); // Include default.
1338   if(!pdml)
1339   {
1340     fprintf(stderr, "MidiInstrument::getMapItem Error: No channel:%d mapping or default found. Using iNewDrumMap.\n", channel);
1341     dest_map = iNewDrumMap[index];
1342     return;
1343   }
1344 
1345   // Always search this instrument's mapping first.
1346   ciPatchDrummapMapping_t ipdm = pdml->find(patch, false); // Don't include defaults here.
1347   if(ipdm == pdml->end())
1348   {
1349     // Not found? Is there a default patch mapping?
1350 #ifdef _USE_INSTRUMENT_OVERRIDES_
1351     if(overrideType & WorkingDrumMapEntry::InstrumentDefaultOverride)
1352 #endif
1353       ipdm = pdml->find(CTRL_PROGRAM_VAL_DONT_CARE, false); // Don't include defaults here.
1354 
1355     if(ipdm == pdml->end())
1356     {
1357       // Not found? Search the global mapping list.
1358       patch_drummap_mapping_list_t* def_pdml = genericMidiInstrument->get_patch_drummap_mapping(channel, false);
1359       if(!def_pdml)
1360       {
1361         //fprintf(stderr, "MidiInstrument::getMapItem Error: No default patch mapping found in genericMidiInstrument. Using iNewDrumMap.\n");
1362         dest_map = iNewDrumMap[index];
1363         return;
1364       }
1365       ipdm = def_pdml->find(patch, false); // Don't include defaults here.
1366       if(ipdm == def_pdml->end())
1367       {
1368         // Not found? Is there a default patch mapping?
1369 #ifdef _USE_INSTRUMENT_OVERRIDES_
1370         if(overrideType & WorkingDrumMapEntry::InstrumentDefaultOverride)
1371 #endif
1372           ipdm = def_pdml->find(CTRL_PROGRAM_VAL_DONT_CARE, false); // Don't include defaults here.
1373 
1374         if(ipdm == def_pdml->end())
1375         {
1376           // Not found? Use the global drum map.
1377           // Update: This shouldn't really happen now, since we have added a default patch drum map to the genericMidiInstrument.
1378           fprintf(stderr, "MidiInstrument::getMapItem Error: No default patch mapping found in genericMidiInstrument. Using iNewDrumMap.\n");
1379           dest_map = iNewDrumMap[index];
1380           return;
1381         }
1382       }
1383     }
1384   }
1385   const patch_drummap_mapping_t& pdm = (*ipdm);
1386 
1387   dest_map = pdm.drummap[index];
1388 
1389 #ifdef _USE_INSTRUMENT_OVERRIDES_
1390   // Did we request to include any instrument overrides?
1391   if(!(overrideType & WorkingDrumMapEntry::InstrumentOverride))
1392     return;
1393 
1394   // Get any instrument overrides.
1395   ciWorkingDrumMapPatch_t iwdp = pdm._workingDrumMapList.find(index);
1396   if(iwdp == pdm._workingDrumMapList.end())
1397     return;
1398 
1399   const WorkingDrumMapEntry& wdm = iwdp->second;
1400 
1401   if(wdm._fields & WorkingDrumMapEntry::NameField)
1402     dest_map.name = wdm._mapItem.name;
1403 
1404   if(wdm._fields & WorkingDrumMapEntry::VolField)
1405     dest_map.vol = wdm._mapItem.vol;
1406 
1407   if(wdm._fields & WorkingDrumMapEntry::QuantField)
1408     dest_map.quant = wdm._mapItem.quant;
1409 
1410   if(wdm._fields & WorkingDrumMapEntry::LenField)
1411     dest_map.len = wdm._mapItem.len;
1412 
1413   if(wdm._fields & WorkingDrumMapEntry::ChanField)
1414     dest_map.channel = wdm._mapItem.channel;
1415 
1416   if(wdm._fields & WorkingDrumMapEntry::PortField)
1417     dest_map.port = wdm._mapItem.port;
1418 
1419   if(wdm._fields & WorkingDrumMapEntry::Lv1Field)
1420     dest_map.lv1 = wdm._mapItem.lv1;
1421 
1422   if(wdm._fields & WorkingDrumMapEntry::Lv2Field)
1423     dest_map.lv2 = wdm._mapItem.lv2;
1424 
1425   if(wdm._fields & WorkingDrumMapEntry::Lv3Field)
1426     dest_map.lv3 = wdm._mapItem.lv3;
1427 
1428   if(wdm._fields & WorkingDrumMapEntry::Lv4Field)
1429     dest_map.lv4 = wdm._mapItem.lv4;
1430 
1431   if(wdm._fields & WorkingDrumMapEntry::ENoteField)
1432     dest_map.enote = wdm._mapItem.enote;
1433 
1434   if(wdm._fields & WorkingDrumMapEntry::ANoteField)
1435     dest_map.anote = wdm._mapItem.anote;
1436 
1437   if(wdm._fields & WorkingDrumMapEntry::MuteField)
1438     dest_map.mute = wdm._mapItem.mute;
1439 
1440   if(wdm._fields & WorkingDrumMapEntry::HideField)
1441     dest_map.hide = wdm._mapItem.hide;
1442 #endif
1443 
1444 }
1445 
findController(int num,int channel,int patch) const1446 MidiController* MidiInstrument::findController(int num, int channel, int patch) const
1447 {
1448 #ifdef MIDNAM_SUPPORT
1449   // Is there a midnam controller list for the given channel and patch?
1450   const MidiControllerList* mcl = _midnamDocument.getControllers(channel, patch);
1451   if(mcl)
1452   {
1453     // Is there a controller for the given num?
1454     MidiController* mc = mcl->findController(num);
1455     if(mc)
1456       // Return that controller.
1457       return mc;
1458   }
1459 #endif
1460   // No midnam controller was found. Does the instrument have the controller?
1461   return controller()->findController(num);
1462 }
1463 
1464 
getControllers(MidiControllerList * dest,int channel,int patch) const1465 void MidiInstrument::getControllers(MidiControllerList* dest, int channel, int patch) const
1466 {
1467   ciMidiController imc;
1468 #ifdef MIDNAM_SUPPORT
1469   // Is there a midnam controller list for the given channel and patch?
1470   const MidiControllerList* mcl = _midnamDocument.getControllers(channel, patch);
1471   if(mcl)
1472   {
1473     // Copy the midnam controller pointers directly to the destination.
1474     // Defer the RPN update until after done.
1475     for(imc = mcl->begin(); imc != mcl->end(); ++imc)
1476       dest->add(imc->second, false);
1477   }
1478 #endif
1479   mcl = controller();
1480   // Copy the instrument controller pointers directly to the destination.
1481   // Defer the RPN update until after done.
1482   for(imc = mcl->begin(); imc != mcl->end(); ++imc)
1483     dest->add(imc->second, false);
1484 
1485   // Be sure to call this since we deferred it above.
1486   dest->update_RPN_Ctrls_Reserved();
1487 }
1488 
1489 #ifdef _USE_INSTRUMENT_OVERRIDES_
isWorkingMapItem(int patch,int index,int fields) const1490 int MidiInstrument::isWorkingMapItem(int patch, int index, int fields) const
1491 {
1492   int ret = WorkingDrumMapEntry::NoOverride;
1493 
1494   // Is there a default patch override for this drum map item?
1495   bool def_ipdm_valid = true;
1496   ciPatchDrummapMapping_t def_ipdm = patch_drummap_mapping.find(CTRL_PROGRAM_VAL_DONT_CARE, false); // Don't include defaults here.
1497   if(def_ipdm == patch_drummap_mapping.end())
1498   {
1499     // Not found? Search the global mapping list.
1500     def_ipdm = genericMidiInstrument->get_patch_drummap_mapping()->find(CTRL_PROGRAM_VAL_DONT_CARE, false);
1501     if(def_ipdm == genericMidiInstrument->get_patch_drummap_mapping()->end())
1502       def_ipdm_valid = false;
1503   }
1504   if(def_ipdm_valid)
1505   {
1506     const patch_drummap_mapping_t& pdm = (*def_ipdm);
1507     ciWorkingDrumMapPatch_t iwdp = pdm._workingDrumMapList.find(index);
1508     if(iwdp != pdm._workingDrumMapList.end())
1509     {
1510       const WorkingDrumMapEntry& wdm = iwdp->second;
1511       if(wdm._fields & fields)
1512         ret |= WorkingDrumMapEntry::InstrumentDefaultOverride;
1513     }
1514   }
1515 
1516   // Is there a patch override for this drum map item?
1517   // Always search this instrument's mapping first.
1518   bool ipdm_valid = true;
1519   ciPatchDrummapMapping_t ipdm = patch_drummap_mapping.find(patch, false);
1520   if(ipdm == patch_drummap_mapping.end())
1521   {
1522     // Not found? Search the global mapping list.
1523     ipdm = MusECore::genericMidiInstrument->get_patch_drummap_mapping()->find(patch, false);
1524     if(ipdm == MusECore::genericMidiInstrument->get_patch_drummap_mapping()->end())
1525       ipdm_valid = false;
1526   }
1527   if(ipdm_valid)
1528   {
1529     const patch_drummap_mapping_t& pdm = (*ipdm);
1530     ciWorkingDrumMapPatch_t iwdp = pdm._workingDrumMapList.find(index);
1531     if(iwdp != pdm._workingDrumMapList.end())
1532     {
1533       const WorkingDrumMapEntry& wdm = iwdp->second;
1534       if(wdm._fields & fields)
1535         ret |= WorkingDrumMapEntry::InstrumentOverride;
1536     }
1537   }
1538 
1539   return ret;
1540 }
1541 
clearDrumMapOverrides()1542 void MidiInstrument::clearDrumMapOverrides()
1543 {
1544   for(iPatchDrummapMapping_t ipdm = patch_drummap_mapping.begin(); ipdm != patch_drummap_mapping.end(); ++ipdm)
1545   {
1546     patch_drummap_mapping_t& pdm = *ipdm;
1547     pdm._workingDrumMapList.clear();
1548   }
1549 }
1550 
setWorkingDrumMapItem(int patch,int index,const WorkingDrumMapEntry & item,bool isReset)1551 bool MidiInstrument::setWorkingDrumMapItem(int patch, int index, const WorkingDrumMapEntry& item, bool isReset)
1552 {
1553   // Special value. Save it from searching.
1554 //   if(patch == CTRL_VAL_UNKNOWN)
1555 //     return false;
1556 
1557 //   iPatchDrummapMapping_t patch_ipm;
1558 //   patch_ipm = patch_drummap_mapping.find(patch);
1559 //   // You can't edit a drum map item in a collection that doesn't exist.
1560 //   if(patch_ipm == patch_drummap_mapping.end())
1561 //     return false;
1562 
1563   // Always search this instrument's mapping first.
1564   iPatchDrummapMapping_t ipdm = patch_drummap_mapping.find(patch, false); // Don't include defaults here.
1565   if(ipdm == patch_drummap_mapping.end())
1566   {
1567     // Not found? Search the global mapping list.
1568     ipdm = MusECore::genericMidiInstrument->get_patch_drummap_mapping()->find(patch, false); // Don't include defaults here.
1569     // Not found? You can't edit a drum map item in a collection that doesn't exist.
1570     if(ipdm == MusECore::genericMidiInstrument->get_patch_drummap_mapping()->end())
1571       return false;
1572   }
1573 
1574   patch_drummap_mapping_t& pdm = *ipdm;
1575 
1576   const int fields = item._fields;
1577 
1578   DrumMap cur_dm;
1579   getMapItem(patch, index, cur_dm, WorkingDrumMapEntry::InstrumentOverride | WorkingDrumMapEntry::InstrumentDefaultOverride);
1580   const int cur_enote = cur_dm.enote;
1581 
1582   if(isReset)
1583     pdm.removeWorkingDrumMapEntry(index, fields);
1584   else
1585     pdm.addWorkingDrumMapEntry(index, item);
1586 
1587   DrumMap new_dm;
1588   getMapItem(patch, index, new_dm, WorkingDrumMapEntry::InstrumentOverride | WorkingDrumMapEntry::InstrumentDefaultOverride);
1589 
1590   if(fields & WorkingDrumMapEntry::ENoteField)
1591   {
1592     int new_enote = new_dm.enote;
1593     int other_index = pdm.drum_in_map[new_enote];
1594     {
1595       DrumMap other_dm;
1596       if(isReset)
1597       {
1598         // Here we need to see the map item value just /before/ any override, so that we can tell
1599         //  whether this other_index brute-force 'reset' value is still technically an
1600         //  override, and either remove or add (modify) the list appropriately.
1601         getMapItem(patch, other_index, other_dm, WorkingDrumMapEntry::InstrumentDefaultOverride);
1602         if(other_dm.enote == cur_enote)
1603         {
1604           // The values are equal. This is technically no longer an override and we may remove it.
1605           //_workingDrumMapPatchList->remove(patch, other_index, WorkingDrumMapEntry::ENoteField);
1606           pdm.removeWorkingDrumMapEntry(other_index, WorkingDrumMapEntry::ENoteField);
1607         }
1608         else
1609         {
1610           // The values are not equal. This is technically still an override, so add (modify) it.
1611           other_dm.enote = cur_enote;
1612           WorkingDrumMapEntry other_wdme(other_dm, WorkingDrumMapEntry::ENoteField);
1613           //_workingDrumMapPatchList->add(patch, other_index, other_wdme);
1614           pdm.addWorkingDrumMapEntry(other_index, other_wdme);
1615         }
1616       }
1617       else
1618       {
1619         other_dm.enote = cur_enote;
1620         WorkingDrumMapEntry other_wdme(other_dm, WorkingDrumMapEntry::ENoteField);
1621         //_workingDrumMapPatchList->add(patch, other_index, other_wdme);
1622         pdm.addWorkingDrumMapEntry(other_index, other_wdme);
1623       }
1624       pdm.drum_in_map[cur_enote] = other_index;
1625       pdm.drum_in_map[new_enote] = index;
1626     }
1627   }
1628 
1629 
1630 
1631 
1632   return true;
1633 }
1634 #endif
1635 
1636 
1637 //---------------------------------------------------------
1638 //   getPatchName
1639 //---------------------------------------------------------
1640 
getPatchName(int,int prog,bool drum,bool includeDefault) const1641 QString MidiInstrument::getPatchName(int /*channel*/, int prog, bool drum, bool includeDefault) const
1642       {
1643   if(MusECore::Patch* p = pg.findPatch(prog, drum, includeDefault))
1644     return p->name;
1645   return "<unknown>";
1646       }
1647 
getNextPatch(int channel,unsigned patch,bool drum)1648 unsigned MidiInstrument::getNextPatch(int channel, unsigned patch, bool drum)
1649 {
1650   QList<dumb_patchlist_entry_t> haystack=getPatches(channel,drum);
1651   if (haystack.empty()) return MusECore::CTRL_VAL_UNKNOWN;
1652 
1653   int prog=patch&0xFF;
1654   int lbank=(patch>>8)&0xFF;
1655   int hbank=(patch>>16)&0xFF;
1656 
1657   dumb_patchlist_entry_t needle=dumb_patchlist_entry_t(prog, (lbank!=0xFF)?lbank:-1, (hbank!=0xFF)?hbank:-1);
1658 
1659   QList<dumb_patchlist_entry_t>::iterator it;
1660   for (it=haystack.begin(); it!=haystack.end(); it++)
1661     if ((*it) == needle)
1662       break;
1663 
1664   if (it==haystack.end()) //not found? use first entry
1665     it=haystack.begin();
1666   else
1667   {
1668     for (;it!=haystack.end(); it++)
1669       if ((*it)!=needle)
1670         break;
1671     if (it==haystack.end()) it=haystack.begin(); //wrap-over
1672   }
1673 
1674   return (it->prog&0xFF)  |
1675          ((((it->lbank==-1)?0xFF:it->lbank)<<8)&0xFF00)  |
1676          ((((it->hbank==-1)?0xFF:it->hbank)<<16)&0xFF0000);
1677 }
1678 
getPrevPatch(int channel,unsigned patch,bool drum)1679 unsigned MidiInstrument::getPrevPatch(int channel, unsigned patch, bool drum)
1680 {
1681   QList<dumb_patchlist_entry_t> haystack=getPatches(channel,drum);
1682   if (haystack.empty()) return MusECore::CTRL_VAL_UNKNOWN;
1683 
1684   int prog=patch&0xFF;
1685   int lbank=(patch>>8)&0xFF;
1686   int hbank=(patch>>16)&0xFF;
1687 
1688   dumb_patchlist_entry_t needle=dumb_patchlist_entry_t(prog, (lbank!=0xFF)?lbank:-1, (hbank!=0xFF)?hbank:-1);
1689 
1690   QList<dumb_patchlist_entry_t>::iterator it;
1691   for (it=haystack.begin(); it!=haystack.end(); it++)
1692     if ((*it) == needle)
1693       break;
1694 
1695   if (it==haystack.end()) //not found? use first entry
1696     it=haystack.begin();
1697   else
1698   {
1699     if (it==haystack.begin()) it=haystack.end(); //wrap-over
1700     it--;
1701   }
1702 
1703   return (it->prog&0xFF)  |
1704          ((((it->lbank==-1)?0xFF:it->lbank)<<8)&0xFF00)  |
1705          ((((it->hbank==-1)?0xFF:it->hbank)<<16)&0xFF0000);
1706 }
1707 
getPatches(int,bool drum)1708 QList<dumb_patchlist_entry_t> MidiInstrument::getPatches(int /*channel*/, bool drum)
1709       {
1710       //int tmask = 1;
1711       QList<dumb_patchlist_entry_t> tmp;
1712 
1713       for (ciPatchGroup i = pg.begin(); i != pg.end(); ++i) {
1714             const PatchList& pl = (*i)->patches;
1715             for (ciPatch ipl = pl.begin(); ipl != pl.end(); ++ipl) {
1716                   const Patch* mp = *ipl;
1717                   if (//(mp->typ & tmask) &&
1718                       (mp->drum == drum))
1719                   {
1720                     int prog = mp->program;
1721                     int lbank = mp->lbank;
1722                     int hbank = mp->hbank;
1723                     tmp.push_back(dumb_patchlist_entry_t(prog,lbank,hbank));
1724                   }
1725             }
1726       }
1727 
1728       return tmp;
1729       }
1730 
1731 
1732 //---------------------------------------------------------
1733 //   patch_drummap_mapping_t
1734 //---------------------------------------------------------
1735 
patch_drummap_mapping_t()1736 patch_drummap_mapping_t::patch_drummap_mapping_t()
1737 {
1738   _patch = CTRL_PROGRAM_VAL_DONT_CARE;
1739   drummap=new DrumMap[128];
1740   for (int i=0;i<128;i++)
1741     drummap[i]=iNewDrumMap[i];
1742   update_drum_in_map();
1743 }
1744 
patch_drummap_mapping_t(const patch_drummap_mapping_t & that)1745 patch_drummap_mapping_t::patch_drummap_mapping_t(const patch_drummap_mapping_t& that)
1746 {
1747   drummap=NULL;
1748   if(that.drummap)
1749   {
1750     drummap=new DrumMap[128];
1751     for (int i=0;i<128;i++)
1752       drummap[i]=that.drummap[i];
1753   }
1754 
1755   _patch = that._patch;
1756   update_drum_in_map();
1757 }
1758 
operator =(const patch_drummap_mapping_t & that)1759 patch_drummap_mapping_t& patch_drummap_mapping_t::operator=(const patch_drummap_mapping_t& that)
1760 {
1761   if (drummap)
1762     delete [] drummap;
1763   drummap=NULL;
1764 
1765   if(that.drummap)
1766   {
1767     drummap=new DrumMap[128];
1768     for (int i=0;i<128;i++)
1769       drummap[i]=that.drummap[i];
1770   }
1771 
1772   _patch = that._patch;
1773 
1774   update_drum_in_map();
1775  return *this;
1776 }
1777 
isValid() const1778 bool patch_drummap_mapping_t::isValid() const
1779 {
1780   return _patch != CTRL_VAL_UNKNOWN && drummap != NULL;
1781 }
1782 
~patch_drummap_mapping_t()1783 patch_drummap_mapping_t::~patch_drummap_mapping_t()
1784 {
1785   if(drummap)
1786     delete [] drummap;
1787 }
1788 
1789 #ifdef _USE_INSTRUMENT_OVERRIDES_
addWorkingDrumMapEntry(int index,const WorkingDrumMapEntry & item)1790 void patch_drummap_mapping_t::addWorkingDrumMapEntry(int index,const WorkingDrumMapEntry& item)
1791 {
1792   _workingDrumMapList.add(index, item);
1793 }
1794 
removeWorkingDrumMapEntry(int index,const WorkingDrumMapEntry & item)1795 void patch_drummap_mapping_t::removeWorkingDrumMapEntry(int index, const WorkingDrumMapEntry& item)
1796 {
1797   _workingDrumMapList.remove(index, item);
1798 }
1799 
removeWorkingDrumMapEntry(int index,int fields)1800 void patch_drummap_mapping_t::removeWorkingDrumMapEntry(int index, int fields)
1801 {
1802   _workingDrumMapList.remove(index, fields);
1803 }
1804 #endif
1805 
update_drum_in_map()1806 void patch_drummap_mapping_t::update_drum_in_map()
1807 {
1808   if(drummap)
1809   {
1810     for(int i = 0; i < 128; ++i)
1811       drum_in_map[(int)drummap[i].enote] = i;
1812   }
1813   else
1814   {
1815     for(int i = 0; i < 128; ++i)
1816       drum_in_map[i] = i;
1817   }
1818 
1819 #ifdef _USE_INSTRUMENT_OVERRIDES_
1820   int index;
1821   int enote;
1822   for(ciWorkingDrumMapPatch_t iwdmp = _workingDrumMapList.begin(); iwdmp != _workingDrumMapList.end(); ++iwdmp)
1823   {
1824     const WorkingDrumMapEntry& wde = iwdmp->second;
1825     if(wde._fields & WorkingDrumMapEntry::ENoteField)
1826     {
1827       index = iwdmp->first;
1828       const DrumMap& dm = wde._mapItem;
1829       enote = (int)dm.enote;
1830       drum_in_map[enote] = index;
1831     }
1832   }
1833 #endif
1834 }
1835 
isPatchInRange(int patch,bool includeDefault) const1836 bool patch_drummap_mapping_t::isPatchInRange(int patch, bool includeDefault) const
1837 {
1838   // No exceptions: If all three prg, hb, and lb are don't care, then patch is always in range.
1839   if(dontCare())
1840     return includeDefault;
1841 
1842   // Special value. Unknown cannot be part of a collection (unless don't care).
1843   if(!isValid() || patch == CTRL_VAL_UNKNOWN)
1844     return false;
1845 
1846   const int hb = (patch >> 16) & 0xff;
1847   const int lb = (patch >> 8) & 0xff;
1848   const int pr = patch & 0xff;
1849 
1850   const bool hboff  = hb >= 128;
1851   const bool lboff  = lb >= 128;
1852   const bool prgoff = pr >= 128; // Shouldn't happen.
1853 
1854   return (programDontCare() || (!prgoff && pr == prog())) &&
1855          (hbankDontCare()   || (!hboff  && hb == hbank())) &&
1856          (lbankDontCare()   || (!lboff  && lb == lbank()));
1857 }
1858 
to_string()1859 QString patch_drummap_mapping_t::to_string()
1860 {
1861   QString tmp;
1862 
1863   if (dontCare())
1864     tmp="default";
1865   else
1866   {
1867     if(hbankDontCare())
1868       tmp += "---";
1869     else
1870       tmp += QString::number(hbank() + 1);
1871 
1872     tmp+=" / ";
1873 
1874     if(lbankDontCare())
1875       tmp += "---";
1876     else
1877       tmp += QString::number(lbank() + 1);
1878 
1879     tmp+=" / ";
1880 
1881     if(programDontCare())
1882       tmp += "---";
1883     else
1884       tmp += QString::number(prog() + 1);
1885   }
1886   return tmp;
1887 }
1888 
1889 //---------------------------------------------------------
1890 //   patch_drummap_mapping_t
1891 //---------------------------------------------------------
1892 
add(const patch_drummap_mapping_list_t & other)1893 void patch_drummap_mapping_list_t::add(const patch_drummap_mapping_list_t& other)
1894 {
1895   for(ciPatchDrummapMapping_t ipdm = other.begin(); ipdm != other.end(); ++ipdm)
1896   {
1897     const patch_drummap_mapping_t& pdm = *ipdm;
1898     add(pdm);
1899   }
1900 }
1901 
add(const patch_drummap_mapping_t & pdm)1902 void patch_drummap_mapping_list_t::add(const patch_drummap_mapping_t& pdm)
1903 {
1904   // No duplicates: If a mapping item by that patch already exists, replace it.
1905   iPatchDrummapMapping_t ipdm = find(pdm._patch, false); // No default.
1906   if(ipdm == end())
1907     push_back(pdm);
1908   else
1909     *ipdm = pdm;
1910 }
1911 
find(int patch,bool includeDefault)1912 iPatchDrummapMapping_t patch_drummap_mapping_list_t::find(int patch, bool includeDefault)
1913 {
1914   iPatchDrummapMapping_t ipdm_default = end();
1915   for(iPatchDrummapMapping_t ipdm = begin(); ipdm != end(); ++ipdm)
1916   {
1917     // Look for an exact match above all else. The given patch must be valid.
1918     if(patch != CTRL_VAL_UNKNOWN && ipdm->_patch == patch)
1919       return ipdm;
1920     // If no exact match is found we'll take a default if found (all three pr, hb, lb = don't care).
1921     if(includeDefault && ipdm->dontCare() && ipdm_default == end())
1922       ipdm_default = ipdm;
1923   }
1924   return ipdm_default;
1925 }
1926 
find(int patch,bool includeDefault) const1927 ciPatchDrummapMapping_t patch_drummap_mapping_list_t::find(int patch, bool includeDefault) const
1928 {
1929   ciPatchDrummapMapping_t ipdm_default = end();
1930   for(ciPatchDrummapMapping_t ipdm = begin(); ipdm != end(); ++ipdm)
1931   {
1932     // Look for an exact match above all else. The given patch must be valid.
1933     if(patch != CTRL_VAL_UNKNOWN && ipdm->_patch == patch)
1934       return ipdm;
1935     // If no exact match is found we'll take a default if found (all three pr, hb, lb = don't care).
1936     if(includeDefault && ipdm->dontCare() && ipdm_default == end())
1937       ipdm_default = ipdm;
1938   }
1939   return ipdm_default;
1940 }
1941 
read(Xml & xml)1942 void patch_drummap_mapping_list_t::read(Xml& xml)
1943 {
1944   int patch = CTRL_PROGRAM_VAL_DONT_CARE;
1945   DrumMap* drummap=new DrumMap[128];
1946   for (int i=0;i<128;i++)
1947     drummap[i]=iNewDrumMap[i];
1948 
1949   for (;;)
1950   {
1951     Xml::Token token = xml.parse();
1952     const QString& tag = xml.s1();
1953     switch (token)
1954     {
1955       case Xml::Error:
1956       case Xml::End:
1957         goto pdml_read_end;
1958 
1959       case Xml::TagStart:
1960         if (tag == "patch_collection")
1961           patch = readDrummapsEntryPatchCollection(xml);
1962         else if (tag == "drummap")
1963           read_new_style_drummap(xml, "drummap", drummap);
1964         else
1965           xml.unknown("patch_drummap_mapping_list_t::read");
1966         break;
1967 
1968       case Xml::TagEnd:
1969         if (tag == "entry")
1970         {
1971           push_back(patch_drummap_mapping_t(drummap, patch));
1972           return;
1973         }
1974 
1975       default:
1976         break;
1977     }
1978   }
1979 
1980 pdml_read_end:
1981   fprintf(stderr, "End or Error in patch_drummap_mapping_list_t::read()!\n");
1982   delete [] drummap;
1983 }
1984 
write(int level,Xml & xml) const1985 void patch_drummap_mapping_list_t::write(int level, Xml& xml) const
1986 {
1987   for (ciPatchDrummapMapping_t it = begin();
1988        it != end(); it++)
1989   {
1990     xml.tag(level++, "entry");
1991 
1992     const patch_drummap_mapping_t& pdm = *it;
1993 
1994     if(!pdm.dontCare())
1995     {
1996       QString tmp="<patch_collection ";
1997 
1998       if(!pdm.programDontCare())
1999         tmp += "prog=\"" + QString::number(pdm.prog()) + QString("\" ");
2000       if(!pdm.lbankDontCare())
2001         tmp += "lbank=\"" + QString::number(pdm.lbank()) + QString("\" ");
2002       if(!pdm.hbankDontCare())
2003         tmp += "hbank=\"" + QString::number(pdm.hbank()) + QString("\" ");
2004 
2005       tmp+="/>\n";
2006 
2007       xml.nput(level, tmp.toLatin1().data());
2008     }
2009 
2010     write_new_style_drummap(level, xml, "drummap", it->drummap);
2011     //write_new_style_drummap(level, xml, "drummap", it->drummap, true); // true = Need to save all entries.
2012 
2013     xml.etag(--level, "entry");
2014   }
2015 }
2016 
2017 #ifdef _USE_INSTRUMENT_OVERRIDES_
writeDrummapOverrides(int level,Xml & xml) const2018 void patch_drummap_mapping_list_t::writeDrummapOverrides(int level, Xml& xml) const
2019 {
2020   for(ciPatchDrummapMapping_t ipdm = begin(); ipdm != end(); ++ipdm)
2021   {
2022     const patch_drummap_mapping_t& pdm = *ipdm;
2023     if(pdm._workingDrumMapList.empty())
2024       continue;
2025     xml.tag(level++, "drumMapPatch patch=\"%d\"", pdm._patch);
2026     pdm._workingDrumMapList.write(level, xml);
2027     xml.etag(--level, "drumMapPatch");
2028   }
2029 }
2030 #endif
2031 
2032 //---------------------------------------------------------
2033 //    WorkingDrumMapEntry
2034 //---------------------------------------------------------
2035 
WorkingDrumMapEntry()2036 WorkingDrumMapEntry::WorkingDrumMapEntry()
2037 {
2038   _fields = NoField;
2039 }
2040 
WorkingDrumMapEntry(const DrumMap & dm,fields_t fields)2041 WorkingDrumMapEntry::WorkingDrumMapEntry(const DrumMap& dm, fields_t fields)
2042 {
2043   _fields = fields;
2044   _mapItem = dm;
2045 }
2046 
WorkingDrumMapEntry(const WorkingDrumMapEntry & other)2047 WorkingDrumMapEntry::WorkingDrumMapEntry(const WorkingDrumMapEntry& other)
2048 {
2049   _fields = other._fields;
2050   _mapItem = other._mapItem;
2051 }
2052 
operator =(const WorkingDrumMapEntry & other)2053 WorkingDrumMapEntry& WorkingDrumMapEntry::operator=(const WorkingDrumMapEntry& other)
2054 {
2055   _fields = other._fields;
2056   _mapItem = other._mapItem;
2057   return *this;
2058 }
2059 
2060 //---------------------------------------------------------
2061 //    WorkingDrumMapList
2062 //---------------------------------------------------------
2063 
add(int index,const WorkingDrumMapEntry & item)2064 void WorkingDrumMapList::add(int index, const WorkingDrumMapEntry& item)
2065 {
2066   WorkingDrumMapPatchInsertResult_t res = insert(WorkingDrumMapPatchInsertPair_t(index, item));
2067   if(res.second == false)
2068   {
2069     iWorkingDrumMapPatch_t& iwp = res.first;
2070     WorkingDrumMapEntry& wde = iwp->second;
2071 
2072     if(item._fields & WorkingDrumMapEntry::NameField)
2073       wde._mapItem.name = item._mapItem.name;
2074 
2075     if(item._fields & WorkingDrumMapEntry::VolField)
2076       wde._mapItem.vol = item._mapItem.vol;
2077 
2078     if(item._fields & WorkingDrumMapEntry::QuantField)
2079       wde._mapItem.quant = item._mapItem.quant;
2080 
2081     if(item._fields & WorkingDrumMapEntry::LenField)
2082       wde._mapItem.len = item._mapItem.len;
2083 
2084     if(item._fields & WorkingDrumMapEntry::ChanField)
2085       wde._mapItem.channel = item._mapItem.channel;
2086 
2087     if(item._fields & WorkingDrumMapEntry::PortField)
2088       wde._mapItem.port = item._mapItem.port;
2089 
2090     if(item._fields & WorkingDrumMapEntry::Lv1Field)
2091       wde._mapItem.lv1 = item._mapItem.lv1;
2092 
2093     if(item._fields & WorkingDrumMapEntry::Lv2Field)
2094       wde._mapItem.lv2 = item._mapItem.lv2;
2095 
2096     if(item._fields & WorkingDrumMapEntry::Lv3Field)
2097       wde._mapItem.lv3 = item._mapItem.lv3;
2098 
2099     if(item._fields & WorkingDrumMapEntry::Lv4Field)
2100       wde._mapItem.lv4 = item._mapItem.lv4;
2101 
2102     if(item._fields & WorkingDrumMapEntry::ENoteField)
2103       wde._mapItem.enote = item._mapItem.enote;
2104 
2105     if(item._fields & WorkingDrumMapEntry::ANoteField)
2106       wde._mapItem.anote = item._mapItem.anote;
2107 
2108     if(item._fields & WorkingDrumMapEntry::MuteField)
2109       wde._mapItem.mute = item._mapItem.mute;
2110 
2111     if(item._fields & WorkingDrumMapEntry::HideField)
2112       wde._mapItem.hide = item._mapItem.hide;
2113 
2114     wde._fields |= item._fields;
2115   }
2116 }
2117 
remove(int index,const WorkingDrumMapEntry & item)2118 int WorkingDrumMapList::remove(int index, const WorkingDrumMapEntry& item)
2119 {
2120   return remove(index, item._fields);
2121 }
2122 
remove(int index,int fields)2123 int WorkingDrumMapList::remove(int index, int fields)
2124 {
2125   iWorkingDrumMapPatch_t iwp = find(index);
2126   if(iwp == end())
2127     return fields;
2128   WorkingDrumMapEntry& wde = iwp->second;
2129   int ret = wde._fields ^ fields;
2130   wde._fields &= ~fields;
2131   ret ^= wde._fields;
2132   if(wde._fields == WorkingDrumMapEntry::NoField)
2133     erase(iwp);
2134   return ret;
2135 }
2136 
read(Xml & xml,bool fillUnused,int defaultIndex)2137 void WorkingDrumMapList::read(Xml& xml, bool fillUnused, int defaultIndex)
2138 {
2139   const QString start_tag = xml.s1();
2140   int index = defaultIndex;
2141   int index_read;
2142   bool enote_read = false;
2143   bool anote_read = false;
2144   bool ok;
2145   WorkingDrumMapEntry wdme;
2146   if(fillUnused)
2147   {
2148     // Must initialize the map item in case some fields aren't given.
2149     wdme._mapItem.init();
2150     // Technically we are overriding all fields even if some are not given.
2151     wdme._fields = WorkingDrumMapEntry::AllFields;
2152   }
2153 
2154   for (;;) {
2155         Xml::Token token = xml.parse();
2156         const QString& tag = xml.s1();
2157         switch (token) {
2158               case Xml::Error:
2159               case Xml::End:
2160                     return;
2161               case Xml::TagStart:
2162                     if (tag == "name")
2163                     {
2164                           wdme._mapItem.name = xml.parse1();
2165                           wdme._fields |= WorkingDrumMapEntry::NameField;
2166                     }
2167                     else if (tag == "vol")
2168                     {
2169                           wdme._mapItem.vol = xml.parseInt();
2170                           wdme._fields |= WorkingDrumMapEntry::VolField;
2171                     }
2172                     else if (tag == "quant")
2173                     {
2174                           wdme._mapItem.quant = xml.parseInt();
2175                           wdme._fields |= WorkingDrumMapEntry::QuantField;
2176                     }
2177                     else if (tag == "len")
2178                     {
2179                           wdme._mapItem.len = xml.parseInt();
2180                           wdme._fields |= WorkingDrumMapEntry::LenField;
2181                     }
2182                     else if (tag == "channel")
2183                     {
2184                           wdme._mapItem.channel = xml.parseInt();
2185                           wdme._fields |= WorkingDrumMapEntry::ChanField;
2186                     }
2187                     else if (tag == "port")
2188                     {
2189                           wdme._mapItem.port = xml.parseInt();
2190                           wdme._fields |= WorkingDrumMapEntry::PortField;
2191                     }
2192                     else if (tag == "lv1")
2193                     {
2194                           wdme._mapItem.lv1 = xml.parseInt();
2195                           wdme._fields |= WorkingDrumMapEntry::Lv1Field;
2196                     }
2197                     else if (tag == "lv2")
2198                     {
2199                           wdme._mapItem.lv2 = xml.parseInt();
2200                           wdme._fields |= WorkingDrumMapEntry::Lv2Field;
2201                     }
2202                     else if (tag == "lv3")
2203                     {
2204                           wdme._mapItem.lv3 = xml.parseInt();
2205                           wdme._fields |= WorkingDrumMapEntry::Lv3Field;
2206                     }
2207                     else if (tag == "lv4")
2208                     {
2209                           wdme._mapItem.lv4 = xml.parseInt();
2210                           wdme._fields |= WorkingDrumMapEntry::Lv4Field;
2211                     }
2212                     else if (tag == "enote")
2213                     {
2214                           wdme._mapItem.enote = xml.parseInt();
2215                           enote_read = true;
2216                           wdme._fields |= WorkingDrumMapEntry::ENoteField;
2217                     }
2218                     else if (tag == "anote")
2219                     {
2220                           wdme._mapItem.anote = xml.parseInt();
2221                           anote_read = true;
2222                           wdme._fields |= WorkingDrumMapEntry::ANoteField;
2223                     }
2224                     else if (tag == "mute")
2225                     {
2226                           wdme._mapItem.mute = xml.parseInt();
2227                           wdme._fields |= WorkingDrumMapEntry::MuteField;
2228                     }
2229                     else if (tag == "hide")
2230                     {
2231                           wdme._mapItem.hide = xml.parseInt();
2232                           wdme._fields |= WorkingDrumMapEntry::HideField;
2233                     }
2234                     else
2235                       xml.unknown(start_tag.toLatin1().constData());
2236                     break;
2237               case Xml::Attribut:
2238                     if (tag == "idx" || tag == "pitch")
2239                     {
2240                       index_read = xml.s2().toInt(&ok);
2241                       if(ok)
2242                         index = index_read;
2243                     }
2244                     break;
2245               case Xml::TagEnd:
2246                     if (tag == start_tag)
2247                     {
2248                       if(index >= 0 && index < 128)
2249                       {
2250                         // If no enote was given, set it to the index.
2251                         if(fillUnused)
2252                         {
2253                           if(!enote_read)
2254                             wdme._mapItem.enote = index;
2255                           // If no anote was given, set it to the enote.
2256                           if(!anote_read)
2257                             wdme._mapItem.anote = wdme._mapItem.enote;
2258                         }
2259                         insert(WorkingDrumMapPatchInsertPair_t(index, wdme));
2260                       }
2261                       return;
2262                     }
2263               default:
2264                     break;
2265               }
2266         }
2267 }
2268 
write(int level,Xml & xml) const2269 void WorkingDrumMapList::write(int level, Xml& xml) const
2270 {
2271   int index;
2272   for(ciWorkingDrumMapPatch_t iwdp = begin(); iwdp != end(); ++iwdp)
2273   {
2274     index = iwdp->first;
2275     xml.tag(level++, "entry idx=\"%d\"", index);
2276 
2277     const WorkingDrumMapEntry& wde = iwdp->second;
2278 
2279     if(wde._fields & WorkingDrumMapEntry::NameField)
2280       xml.strTag(level, "name", wde._mapItem.name);
2281 
2282     if(wde._fields & WorkingDrumMapEntry::VolField)
2283       xml.intTag(level, "vol", wde._mapItem.vol);
2284 
2285     if(wde._fields & WorkingDrumMapEntry::QuantField)
2286       xml.intTag(level, "quant", wde._mapItem.quant);
2287 
2288     if(wde._fields & WorkingDrumMapEntry::LenField)
2289       xml.intTag(level, "len", wde._mapItem.len);
2290 
2291     if(wde._fields & WorkingDrumMapEntry::ChanField)
2292       xml.intTag(level, "channel", wde._mapItem.channel);
2293 
2294     if(wde._fields & WorkingDrumMapEntry::PortField)
2295       xml.intTag(level, "port", wde._mapItem.port);
2296 
2297     if(wde._fields & WorkingDrumMapEntry::Lv1Field)
2298       xml.intTag(level, "lv1", wde._mapItem.lv1);
2299 
2300     if(wde._fields & WorkingDrumMapEntry::Lv2Field)
2301       xml.intTag(level, "lv2", wde._mapItem.lv2);
2302 
2303     if(wde._fields & WorkingDrumMapEntry::Lv3Field)
2304       xml.intTag(level, "lv3", wde._mapItem.lv3);
2305 
2306     if(wde._fields & WorkingDrumMapEntry::Lv4Field)
2307       xml.intTag(level, "lv4", wde._mapItem.lv4);
2308 
2309     if(wde._fields & WorkingDrumMapEntry::ENoteField)
2310       xml.intTag(level, "enote", wde._mapItem.enote);
2311 
2312     if(wde._fields & WorkingDrumMapEntry::ANoteField)
2313       xml.intTag(level, "anote", wde._mapItem.anote);
2314 
2315     if(wde._fields & WorkingDrumMapEntry::MuteField)
2316       xml.intTag(level, "mute", wde._mapItem.mute);
2317 
2318     if(wde._fields & WorkingDrumMapEntry::HideField)
2319       xml.intTag(level, "hide", wde._mapItem.hide);
2320 
2321     xml.tag(--level, "/entry");
2322   }
2323 }
2324 
2325 
2326 //---------------------------------------------------------
2327 //    WorkingDrumMapInstrumentList
2328 //---------------------------------------------------------
2329 
read(Xml & xml)2330 void WorkingDrumMapInstrumentList::read(Xml& xml)
2331 {
2332   const QString start_tag = xml.s1();
2333   QString instr_name;
2334   WorkingDrumMapPatchList wdmpl;
2335   for (;;) {
2336         Xml::Token token = xml.parse();
2337         const QString& tag = xml.s1();
2338         switch (token) {
2339               case Xml::Error:
2340               case Xml::End:
2341                     return;
2342               case Xml::TagStart:
2343                     if (tag == "drumMapPatch")
2344                       // false = Do not fill in unused items.
2345                       wdmpl.read(xml, false);
2346                     else
2347                       xml.unknown(start_tag.toLatin1().constData());
2348                     break;
2349               case Xml::Attribut:
2350                     if (tag == "instrument")
2351                     {
2352                       instr_name = xml.s2();
2353                     }
2354                     break;
2355               case Xml::TagEnd:
2356                     if (tag == start_tag)
2357                     {
2358                       if(!instr_name.isEmpty() && !wdmpl.empty())
2359                         insert(WorkingDrumMapInstrumentListInsertPair_t(instr_name.toStdString(), wdmpl));
2360                       return;
2361                     }
2362               default:
2363                     break;
2364               }
2365         }
2366 }
2367 
2368 
2369 //---------------------------------------------------------
2370 //    WorkingDrumMapPatchList
2371 //---------------------------------------------------------
2372 
add(const WorkingDrumMapPatchList & other)2373 void WorkingDrumMapPatchList::add(const WorkingDrumMapPatchList& other)
2374 {
2375   int patch;
2376   int index;
2377   for(ciWorkingDrumMapPatchList_t iwdmpl = other.begin(); iwdmpl != other.end(); ++iwdmpl)
2378   {
2379     patch = iwdmpl->first;
2380     const WorkingDrumMapList& wdml = iwdmpl->second;
2381     WorkingDrumMapPatchListInsertResult_t res = insert(WorkingDrumMapPatchListInsertPair_t(patch, wdml));
2382     iWorkingDrumMapPatchList_t res_iwdmpl = res.first;
2383     if(res_iwdmpl == end()) // Error.
2384       continue;
2385     WorkingDrumMapList& res_wdml = res_iwdmpl->second;
2386     for(iWorkingDrumMapPatch_t res_iwdp = res_wdml.begin(); res_iwdp != res_wdml.end(); ++res_iwdp)
2387     {
2388       index = res_iwdp->first;
2389       WorkingDrumMapEntry& wdme = res_iwdp->second;
2390       res_wdml.add(index, wdme);
2391     }
2392   }
2393 }
2394 
add(int patch,const WorkingDrumMapList & list)2395 void WorkingDrumMapPatchList::add(int patch, const WorkingDrumMapList& list)
2396 {
2397   insert(WorkingDrumMapPatchListInsertPair_t(patch, list));
2398 }
2399 
add(int patch,int index,const WorkingDrumMapEntry & item)2400 void WorkingDrumMapPatchList::add(int patch, int index, const WorkingDrumMapEntry& item)
2401 {
2402   WorkingDrumMapPatchListInsertResult_t res = insert(WorkingDrumMapPatchListInsertPair_t(patch, WorkingDrumMapList()));
2403   iWorkingDrumMapPatchList_t iwdmpl = res.first;
2404   if(iwdmpl == end())  // Error, should exist.
2405     return;
2406   WorkingDrumMapList& wdml = iwdmpl->second;
2407   wdml.add(index, item);
2408 }
2409 
remove(int patch,int index,const WorkingDrumMapEntry & item,bool includeDefault)2410 void WorkingDrumMapPatchList::remove(int patch, int index, const WorkingDrumMapEntry& item, bool includeDefault)
2411 {
2412   remove(patch, index, item._fields, includeDefault);
2413 }
2414 
remove(int patch,int index,int fields,bool includeDefault)2415 void WorkingDrumMapPatchList::remove(int patch, int index, int fields, bool includeDefault)
2416 {
2417   // Remove requested fields from the exact patch number first.
2418   iWorkingDrumMapPatchList_t iwdmpl = WorkingDrumMapPatchList_t::find(patch);
2419   if(iwdmpl != end())
2420   {
2421     WorkingDrumMapList& wdml = iwdmpl->second;
2422     // Consider defaults and real patch overrides as part of the same deal,
2423     //  remove all requested fields from BOTH.
2424     //fields = wdml.remove(index, fields);
2425     wdml.remove(index, fields);
2426     // No more items in the list? Remove this container list.
2427     if(wdml.empty())
2428       erase(iwdmpl);
2429   }
2430 
2431   // Consider defaults and real patch overrides as part of the same deal,
2432   //  remove all requested fields from BOTH.
2433   //if(includeDefault && fields != WorkingDrumMapEntry::NoField)
2434   if(includeDefault)
2435   {
2436     iwdmpl = WorkingDrumMapPatchList_t::find(CTRL_PROGRAM_VAL_DONT_CARE);
2437     if(iwdmpl != end())
2438     {
2439       WorkingDrumMapList& wdml = iwdmpl->second;
2440       wdml.remove(index, fields);
2441       // No more items in the list? Remove this container list.
2442       if(wdml.empty())
2443         erase(iwdmpl);
2444     }
2445   }
2446 }
2447 
remove(int patch,bool includeDefault)2448 void WorkingDrumMapPatchList::remove(int patch, bool includeDefault)
2449 {
2450   // Remove requested fields from the exact patch number first.
2451   iWorkingDrumMapPatchList_t iwdmpl = WorkingDrumMapPatchList_t::find(patch);
2452   if(iwdmpl != end())
2453     erase(iwdmpl);
2454   // Patch map not found? Look for a default patch number (all three pr, hb, lb = don't care).
2455   else if(includeDefault)
2456   {
2457     iwdmpl = WorkingDrumMapPatchList_t::find(CTRL_PROGRAM_VAL_DONT_CARE);
2458     if(iwdmpl != end())
2459       erase(iwdmpl);
2460   }
2461 }
2462 
find(int patch,bool includeDefault)2463 WorkingDrumMapList* WorkingDrumMapPatchList::find(int patch, bool includeDefault)
2464 {
2465   // Look for an exact match above all else. The given patch must be valid.
2466   iWorkingDrumMapPatchList_t iwdmpl = WorkingDrumMapPatchList_t::find(patch);
2467   // If no exact match is found we'll take a default if found (all three pr, hb, lb = don't care).
2468   if(iwdmpl == end())
2469   {
2470     if(!includeDefault)
2471       return NULL;
2472     iwdmpl = WorkingDrumMapPatchList_t::find(CTRL_PROGRAM_VAL_DONT_CARE);
2473     if(iwdmpl == end())
2474       return NULL;
2475   }
2476   return &iwdmpl->second;
2477 }
2478 
find(int patch,bool includeDefault) const2479 const WorkingDrumMapList* WorkingDrumMapPatchList::find(int patch, bool includeDefault) const
2480 {
2481   // Look for an exact match above all else. The given patch must be valid.
2482   ciWorkingDrumMapPatchList_t iwdmpl = WorkingDrumMapPatchList_t::find(patch);
2483   // If no exact match is found we'll take a default if found (all three pr, hb, lb = don't care).
2484   if(iwdmpl == end())
2485   {
2486     if(!includeDefault)
2487       return NULL;
2488     iwdmpl = WorkingDrumMapPatchList_t::find(CTRL_PROGRAM_VAL_DONT_CARE);
2489     if(iwdmpl == end())
2490       return NULL;
2491   }
2492   return &iwdmpl->second;
2493 }
2494 
find(int patch,int index,bool includeDefault)2495 WorkingDrumMapEntry* WorkingDrumMapPatchList::find(int patch, int index, bool includeDefault)
2496 {
2497   WorkingDrumMapList* wdmpl = find(patch, includeDefault);
2498   if(!wdmpl)
2499     return NULL;
2500   iWorkingDrumMapPatch_t iwdmp = wdmpl->find(index);
2501   if(iwdmp == wdmpl->end())
2502     return NULL;
2503   return &iwdmp->second;
2504 }
2505 
find(int patch,int index,bool includeDefault) const2506 const WorkingDrumMapEntry* WorkingDrumMapPatchList::find(int patch, int index, bool includeDefault) const
2507 {
2508   const WorkingDrumMapList* wdmpl = find(patch, includeDefault);
2509   if(!wdmpl)
2510     return NULL;
2511   ciWorkingDrumMapPatch_t iwdmp = wdmpl->find(index);
2512   if(iwdmp == wdmpl->end())
2513     return NULL;
2514   return &iwdmp->second;
2515 }
2516 
read(Xml & xml,bool fillUnused)2517 void WorkingDrumMapPatchList::read(Xml& xml, bool fillUnused)
2518 {
2519   const QString start_tag = xml.s1();
2520   // Default "don't care" patch number, in case no patch number found.
2521   int patch = 0xffffff;
2522   int patch_read;
2523   bool ok;
2524   int index = 0;
2525   WorkingDrumMapList wdml;
2526 
2527 // TODO Need to move this stuff up into the caller, because a default patch map may not have been loaded yet!
2528 // For now, we rely on the loaded map being trustworthy with no duplicate enotes. Still the situation IS compensated
2529 //  for at the lowest level in MidiTrack::normalizeDrumMap(), so it IS tolerant of mistakes in the loaded map.
2530 //
2531 // REMOVE Tim. newdrums. Removed.
2532 //   WorkingDrumMapList* def_wdml = 0;
2533 //   //if(patch != CTRL_PROGRAM_VAL_DONT_CARE)
2534 //     def_wdml = find(CTRL_PROGRAM_VAL_DONT_CARE, false);
2535 //   WorkingDrumMapEntry new_wdme;
2536 //   // We can init these outside of the loop.
2537 //   new_wdme._fields = WorkingDrumMapEntry::AllFields;
2538 //   new_wdme._mapItem.init();
2539 //
2540 //   bool used_index[128];
2541 //   int used_enotes[128];
2542 //   for(int i = 0; i < 128; ++i)
2543 //   {
2544 //     used_index[i] = false;
2545 //     used_enotes[i] = 0;
2546 //   }
2547 //   char unused_enotes[128];
2548 //   int unused_enotes_sz = 0;
2549 //   char unused_index[128];
2550 //   int unused_index_sz = 0;
2551 
2552   for (;;) {
2553         Xml::Token token = xml.parse();
2554         const QString& tag = xml.s1();
2555         switch (token) {
2556               case Xml::Error:
2557               case Xml::End:
2558                     return;
2559               case Xml::TagStart:
2560                     if (tag == "entry")
2561                     {
2562                       // In case there are no index attributes in this drum map,
2563                       //  we use a running index.
2564                       wdml.read(xml, fillUnused, index);
2565                       ++index;
2566                     }
2567                     else if (tag == "comment")
2568                       xml.parse();
2569                     else
2570                       xml.unknown(start_tag.toLatin1().constData());
2571                     break;
2572               case Xml::Attribut:
2573                     if (tag == "patch")
2574                     {
2575                       patch_read = xml.s2().toInt(&ok);
2576                       if(ok)
2577                         patch = patch_read;
2578                     }
2579                     break;
2580               case Xml::TagEnd:
2581                     if (tag == start_tag)
2582                     {
2583 
2584                       if(!wdml.empty())
2585                       {
2586 // //                         // We can only deal with duplicate enotes here if requesting to
2587 // //                         //  fill up all items, because in the context of further overrides
2588 // //                         //  masking any unused ones here, we cannot fully know which enotes are used.
2589 //                         //if(fillUnused)
2590 //                         //{
2591 //                           // Find all the used enotes and indexes.
2592 //                           for(iWorkingDrumMapPatch_t iwdml = wdml.begin(); iwdml != wdml.end(); ++iwdml)
2593 //                           {
2594 //                             used_index[iwdml->first] = true;
2595 //                             ++used_enotes[(unsigned char)iwdml->second._mapItem.enote];
2596 //                           }
2597 //
2598 //                           // Find all the unused enotes and indexes.
2599 //                           for(int i = 0; i < 128; ++i)
2600 //                           {
2601 //                             if(!used_index[i])
2602 //                               unused_index[unused_index_sz++] = i;
2603 //                             if(used_enotes[i] == 0)
2604 //                               unused_enotes[unused_enotes_sz++] = i;
2605 //                           }
2606 //
2607 //                           // Ensure there are NO duplicate enotes in the existing map items so far.
2608 //                           int unused_enotes_cnt = 0;
2609 //                           for(iWorkingDrumMapPatch_t iwdml = wdml.begin(); iwdml != wdml.end(); ++iwdml)
2610 //                           {
2611 //                             // More than 1 (this) usage?
2612 //                             if(used_enotes[(unsigned char)iwdml->second._mapItem.enote] > 1)
2613 //                             {
2614 //                               if(unused_enotes_cnt >= unused_enotes_sz)
2615 //                               {
2616 //                                 fprintf(stderr, "WorkingDrumMapPatchList::read: Error: unused_enotes_cnt >= unused_enotes_sz:%d\n",
2617 //                                         unused_enotes_sz);
2618 //                                 break;
2619 //                               }
2620 //                               --used_enotes[(unsigned char)iwdml->second._mapItem.enote];
2621 //                               iwdml->second._mapItem.enote = unused_enotes[unused_enotes_cnt++];
2622 //                             }
2623 //                           }
2624 //
2625 //                           // Technically we are overriding the entire map, even if some map items weren't given.
2626 //                           // In case of loading a partial or incomplete map, ensure that all 128 map items are filled.
2627 //                           for(int i = 0; i < unused_index_sz; ++i)
2628 //                           {
2629 //                             if(unused_enotes_cnt >= unused_enotes_sz)
2630 //                             {
2631 //                               fprintf(stderr, "WorkingDrumMapPatchList::read: Error filling unused items: unused_enotes_cnt >= unused_enotes_sz:%d\n",
2632 //                                       unused_enotes_sz);
2633 //                               break;
2634 //                             }
2635 //                             // Set the enote.
2636 //                             new_wdme._mapItem.enote = unused_enotes[unused_enotes_cnt++];
2637 //                             // Might as well set the anote to enote.
2638 //                             new_wdme._mapItem.anote = new_wdme._mapItem.enote;
2639 //                             // Insert the item at the unused index.
2640 //                             wdml.insert(WorkingDrumMapPatchInsertPair_t(unused_index[i], new_wdme));
2641 //                           }
2642 //                         //}
2643 
2644                         // Insert the working drum map list at the patch.
2645                         insert(WorkingDrumMapPatchListInsertPair_t(patch, wdml));
2646                       }
2647                       return;
2648                     }
2649               default:
2650                     break;
2651               }
2652         }
2653 }
2654 
write(int level,Xml & xml) const2655 void WorkingDrumMapPatchList::write(int level, Xml& xml) const
2656 {
2657   int patch;
2658   for(ciWorkingDrumMapPatchList_t iwdpl = begin(); iwdpl != end(); ++iwdpl)
2659   {
2660     const WorkingDrumMapList& wdml = iwdpl->second;
2661     if(wdml.empty())
2662       continue;
2663     patch = iwdpl->first;
2664     xml.tag(level++, "drumMapPatch patch=\"%d\"", patch);
2665     wdml.write(level, xml);
2666     xml.etag(--level, "drumMapPatch");
2667   }
2668 }
2669 
2670 
2671 //---------------------------------------------------------
2672 //    ChannelDrumMappingList
2673 //---------------------------------------------------------
2674 
ChannelDrumMappingList()2675 ChannelDrumMappingList::ChannelDrumMappingList()
2676 {
2677   // Ensure there is always a default channel.
2678   // Initialize with a default drum map on default channel. Patch is default 0xffffff. GM-1 does not specify a drum patch number.
2679   add(-1, patch_drummap_mapping_list_t());
2680 }
2681 
add(const ChannelDrumMappingList & other)2682 void ChannelDrumMappingList::add(const ChannelDrumMappingList& other)
2683 {
2684   int channel;
2685 
2686   for(ciChannelDrumMappingList_t icdml = other.begin(); icdml != other.end(); ++icdml)
2687   {
2688     channel = icdml->first;
2689     const patch_drummap_mapping_list_t& pdml = icdml->second;
2690     add(channel, pdml);
2691   }
2692 }
2693 
add(int channel,const patch_drummap_mapping_list_t & list)2694 void ChannelDrumMappingList::add(int channel, const patch_drummap_mapping_list_t& list)
2695 {
2696   ChannelDrumMappingListInsertResult_t res = insert(ChannelDrumMappingListInsertPair_t(channel, list));
2697   if(res.second == false)
2698   {
2699     iChannelDrumMappingList_t res_icdml = res.first;
2700     patch_drummap_mapping_list_t& res_pdml = res_icdml->second;
2701     res_pdml.add(list);
2702   }
2703 }
2704 
find(int channel,bool includeDefault)2705 patch_drummap_mapping_list_t* ChannelDrumMappingList::find(int channel, bool includeDefault)
2706 {
2707   // Look for an exact match above all else. The given channel must be valid.
2708   iChannelDrumMappingList_t icdml = ChannelDrumMappingList_t::find(channel);
2709   // If no exact match is found we'll take a default if found.
2710   if(icdml == end())
2711   {
2712     if(!includeDefault)
2713       return NULL;
2714     icdml = ChannelDrumMappingList_t::find(-1);
2715     if(icdml == end())
2716       return NULL;
2717   }
2718   return &icdml->second;
2719 }
2720 
find(int channel,bool includeDefault) const2721 const patch_drummap_mapping_list_t* ChannelDrumMappingList::find(int channel, bool includeDefault) const
2722 {
2723   // Look for an exact match above all else. The given channel must be valid.
2724   ciChannelDrumMappingList_t icdml = ChannelDrumMappingList_t::find(channel);
2725   // If no exact match is found we'll take a default if found.
2726   if(icdml == end())
2727   {
2728     if(!includeDefault)
2729       return NULL;
2730     icdml = ChannelDrumMappingList_t::find(-1);
2731     if(icdml == end())
2732       return NULL;
2733   }
2734   return &icdml->second;
2735 }
2736 
read(Xml & xml)2737 void ChannelDrumMappingList::read(Xml& xml)
2738 {
2739   const QString start_tag = xml.s1();
2740   // Default "don't care" channel number, in case no channel number found.
2741   int channel = -1; // Default.
2742   int channel_read;
2743   bool ok;
2744 
2745   for (;;) {
2746         Xml::Token token = xml.parse();
2747         const QString& tag = xml.s1();
2748         switch (token) {
2749               case Xml::Error:
2750               case Xml::End:
2751                     return;
2752               case Xml::TagStart:
2753                     if (tag == "entry")
2754                     {
2755                       patch_drummap_mapping_list_t pdml;
2756                       pdml.read(xml);
2757                       if(!pdml.empty())
2758                         add(channel, pdml);
2759                     }
2760                     else if (tag == "comment")
2761                       xml.parse();
2762                     else
2763                       xml.unknown(start_tag.toLatin1().constData());
2764                     break;
2765               case Xml::Attribut:
2766                     if (tag == "channel")
2767                     {
2768                       channel_read = xml.s2().toInt(&ok);
2769                       if(ok)
2770                         channel = channel_read;
2771                     }
2772                     break;
2773               case Xml::TagEnd:
2774                     if (tag == start_tag)
2775                       return;
2776               default:
2777                     break;
2778               }
2779         }
2780 }
2781 
write(int level,Xml & xml) const2782 void ChannelDrumMappingList::write(int level, Xml& xml) const
2783 {
2784   int channel;
2785 
2786   // Count the items used.
2787   int sz = 0;
2788   for(ciChannelDrumMappingList_t icdml = begin(); icdml != end(); ++icdml)
2789   {
2790     const patch_drummap_mapping_list_t& pdml = icdml->second;
2791     if(pdml.empty())
2792       continue;
2793     ++sz;
2794   }
2795 
2796   for(ciChannelDrumMappingList_t icdml = begin(); icdml != end(); ++icdml)
2797   {
2798     const patch_drummap_mapping_list_t& pdml = icdml->second;
2799     if(pdml.empty())
2800       continue;
2801     channel = icdml->first;
2802 
2803     // Don't bother with the drumMapChannel tag if not required.
2804     if(sz >= 2 || channel != -1) // -1 is default.
2805       xml.tag(level++, "drumMapChannel channel=\"%d\"", channel);
2806 
2807     pdml.write(level, xml);
2808 
2809     if(sz >= 2 || channel != -1) // -1 is default.
2810       xml.etag(--level, "drumMapChannel");
2811   }
2812 }
2813 
2814 } // namespace MusECore
2815