1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
2 
3 /*
4     Rosegarden
5     A sequencer and musical notation editor.
6     Copyright 2000-2021 the Rosegarden development team.
7     See the AUTHORS file for more details.
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 as
11     published by the Free Software Foundation; either version 2 of the
12     License, or (at your option) any later version.  See the file
13     COPYING included with this distribution for more information.
14 */
15 
16 #define RG_MODULE_STRING "[MidiDevice]"
17 
18 #include "MidiDevice.h"
19 #include "sound/Midi.h"  // For MIDI_CONTROLLER_VOLUME, etc...
20 #include "base/AllocateChannels.h"
21 #include "base/ControlParameter.h"
22 #include "base/Instrument.h"
23 #include "base/MidiTypes.h"
24 #include "misc/Debug.h"
25 
26 #include <cstdio>
27 #include <cstdlib>
28 #include <iostream>
29 #include <set>
30 
31 #include <sstream>
32 
33 #include <QString>
34 
35 namespace Rosegarden
36 {
37 
38 #if 0
39 MidiDevice::MidiDevice():
40     Device(0, "Default Midi Device", Device::Midi),
41     m_metronome(0),
42     m_direction(Play),
43     m_variationType(NoVariations),
44     m_librarian(std::pair<std::string, std::string>("<none>", "<none>")),
45     m_allocator(new AllocateChannels(ChannelSetup::MIDI))
46 {
47     createInstruments(MidiInstrumentBase);
48     generatePresentationList();
49     generateDefaultControllers();
50     deviceToInstrControllerPush();
51 
52     // create a default Metronome
53     m_metronome = new MidiMetronome(MidiInstrumentBase + 9);
54 }
55 #endif
56 
MidiDevice(DeviceId id,InstrumentId ibase,const std::string & name,DeviceDirection dir)57 MidiDevice::MidiDevice(DeviceId id,
58                        InstrumentId ibase,
59                        const std::string &name,
60                        DeviceDirection dir):
61     Device(id, name, Device::Midi),
62     m_metronome(nullptr),
63     m_direction(dir),
64     m_variationType(NoVariations),
65     m_librarian(std::pair<std::string, std::string>("<none>", "<none>")),
66     m_allocator(new AllocateChannels(ChannelSetup::MIDI))
67 {
68     createInstruments(ibase);
69     generatePresentationList();
70     generateDefaultControllers();
71     deviceToInstrControllerPush();
72 
73     // create a default Metronome
74     m_metronome = new MidiMetronome(MidiInstrumentBase + 9);
75 }
76 
77 #if 0
78 MidiDevice::MidiDevice(DeviceId id,
79                        InstrumentId ibase,
80                        const MidiDevice &dev) :
81     Device(id, dev.getName(), Device::Midi),
82     m_programList(dev.m_programList),
83     m_bankList(dev.m_bankList),
84     m_controlList(0),
85     m_keyMappingList(dev.m_keyMappingList),
86     m_metronome(0),
87     m_direction(dev.getDirection()),
88     m_variationType(dev.getVariationType()),
89     m_librarian(dev.getLibrarian()),
90     m_allocator(new AllocateChannels(ChannelSetup::MIDI))
91 {
92     createInstruments(ibase);
93 
94     // Populate device and Instrument with Controllers.
95     ControlList::const_iterator cIt = dev.m_controlList.begin();
96     for(; cIt != dev.m_controlList.end(); ++cIt) {
97         addControlParameter(*cIt, true);
98     }
99 
100 
101     // Create and assign a metronome if required
102     //
103     if (dev.getMetronome()) {
104         m_metronome = new MidiMetronome(*dev.getMetronome());
105     }
106 
107     generatePresentationList();
108 }
109 #endif
110 
MidiDevice(const MidiDevice & dev)111 MidiDevice::MidiDevice(const MidiDevice &dev) :
112     Device(dev.getId(), dev.getName(), dev.getType()),
113     Controllable(),
114     m_programList(dev.m_programList),
115     m_bankList(dev.m_bankList),
116     m_controlList(dev.m_controlList),
117     m_keyMappingList(dev.m_keyMappingList),
118     m_metronome(nullptr),
119     m_direction(dev.getDirection()),
120     m_variationType(dev.getVariationType()),
121     m_librarian(dev.getLibrarian()),
122     m_allocator(new AllocateChannels(ChannelSetup::MIDI))
123 {
124     // Create and assign a metronome if required
125     //
126     if (dev.getMetronome())
127     {
128         m_metronome = new MidiMetronome(*dev.getMetronome());
129     }
130 
131     // Copy the instruments
132     //
133     InstrumentList insList = dev.getAllInstruments();
134     InstrumentList::iterator iIt = insList.begin();
135     for (; iIt != insList.end(); ++iIt)
136     {
137         Instrument *newInst = new Instrument(**iIt);
138         newInst->setDevice(this);
139         m_instruments.push_back(newInst);
140     }
141 
142     // generate presentation instruments
143     generatePresentationList();
144 }
145 
146 #if 0
147 MidiDevice &
148 MidiDevice::operator=(const MidiDevice &dev)
149 {
150     if (&dev == this) return *this;
151 
152     m_id = dev.getId();
153     m_name = dev.getName();
154     m_type = dev.getType();
155     m_librarian = dev.getLibrarian();
156 
157     m_keyMappingList = dev.getKeyMappings(),
158     m_programList = dev.getPrograms();
159     m_bankList = dev.getBanks();
160     m_controlList = dev.getControlParameters();
161     m_direction = dev.getDirection();
162     m_variationType = dev.getVariationType();
163 
164     // clear down instruments list
165     m_instruments.clear();
166     m_presentationInstrumentList.clear();
167 
168     // Create and assign a metronome if required
169     //
170     if (dev.getMetronome())
171     {
172         if (m_metronome) delete m_metronome;
173         m_metronome = new MidiMetronome(*dev.getMetronome());
174     }
175     else
176     {
177         delete m_metronome;
178         m_metronome = 0;
179     }
180 
181     if (m_allocator) { delete m_allocator; }
182     m_allocator = new AllocateChannels(ChannelSetup::MIDI);
183 
184     // Copy the instruments
185     //
186     InstrumentList insList = dev.getAllInstruments();
187     InstrumentList::iterator iIt = insList.begin();
188     for (; iIt != insList.end(); ++iIt)
189     {
190         Instrument *newInst = new Instrument(**iIt);
191         newInst->setDevice(this);
192         m_instruments.push_back(newInst);
193     }
194 
195     // generate presentation instruments
196     generatePresentationList();
197 
198     return (*this);
199 }
200 #endif
201 
~MidiDevice()202 MidiDevice::~MidiDevice()
203 {
204     delete m_metronome;
205     delete m_allocator;
206 
207     //!!! delete key mappings
208 }
209 
210 AllocateChannels *
getAllocator()211 MidiDevice::getAllocator()
212 { return m_allocator; }
213 
214 void
createInstruments(InstrumentId base)215 MidiDevice::createInstruments(InstrumentId base)
216 {
217     for (int i = 0; i < 16; ++i) {
218         Instrument *instrument = new Instrument
219             (base + i, Instrument::Midi, "", i, this);
220         instrument->setFixedChannel();
221         // ??? Since we don't have a connection yet, this makes
222         //     little sense.
223         //instrument->sendChannelSetup();
224         addInstrument(instrument);
225     }
226     renameInstruments();
227 }
228 
229 void
renameInstruments()230 MidiDevice::renameInstruments()
231 {
232     for (int i = 0; i < 16; ++i) {
233         m_instruments[i]->setName
234             (QString("%1 #%2%3")
235              .arg(getName().c_str())
236              .arg(i+1)
237              .arg(isPercussionNumber(i) ? "[D]" : "")
238              .toUtf8().data());
239     }
240 }
241 
242 void
generatePresentationList()243 MidiDevice::generatePresentationList()
244 {
245     // Fill the presentation list for the instruments
246     //
247     m_presentationInstrumentList.clear();
248 
249     InstrumentList::iterator it;
250     for (it = m_instruments.begin(); it != m_instruments.end(); ++it)
251     {
252         if ((*it)->getId() >= MidiInstrumentBase) {
253             m_presentationInstrumentList.push_back(*it);
254         }
255     }
256 }
257 
258 void
generateDefaultControllers()259 MidiDevice::generateDefaultControllers()
260 {
261     m_controlList.clear();
262 
263     static std::string controls[][9] = {
264         { "Pan", Rosegarden::Controller::EventType, "<none>", "0", "127", "64", "10", "2", "0" },
265         { "Chorus", Rosegarden::Controller::EventType, "<none>", "0", "127", "0", "93", "3", "1" },
266         { "Volume", Rosegarden::Controller::EventType, "<none>", "0", "127", "100", "7", "1", "2" },
267         { "Reverb", Rosegarden::Controller::EventType, "<none>", "0", "127", "0", "91", "3", "3" },
268         { "Sustain", Rosegarden::Controller::EventType, "<none>", "0", "127", "0", "64", "4", "-1" },
269         { "Expression", Rosegarden::Controller::EventType, "<none>", "0", "127", "127", "11", "2", "-1" },
270         { "Modulation", Rosegarden::Controller::EventType, "<none>", "0", "127", "0", "1", "4", "-1" },
271         { "PitchBend", Rosegarden::PitchBend::EventType, "<none>", "0", "16383", "8192", "1", "4", "-1" }
272     };
273 
274     for (size_t i = 0; i < sizeof(controls) / sizeof(controls[0]); ++i) {
275 
276         Rosegarden::ControlParameter con(controls[i][0],
277                                          controls[i][1],
278                                          controls[i][2],
279                                          atoi(controls[i][3].c_str()),
280                                          atoi(controls[i][4].c_str()),
281                                          atoi(controls[i][5].c_str()),
282                                          Rosegarden::MidiByte(atoi(controls[i][6].c_str())),
283                                          atoi(controls[i][7].c_str()),
284                                          atoi(controls[i][8].c_str()));
285         addControlParameter(con, false);
286     }
287 }
288 
289 void
deviceToInstrControllerPush()290 MidiDevice::deviceToInstrControllerPush()
291 {
292     // Copy the instruments
293     //
294 
295     InstrumentList::iterator iIt = m_instruments.begin();
296     for (; iIt != m_instruments.end(); ++iIt)
297     {
298         (*iIt)->clearStaticControllers();
299         ControlList::const_iterator cIt = m_controlList.begin();
300         for (; cIt != m_controlList.end(); ++cIt)
301         {
302             // It appears -1 means not to display an IPB controller
303             if (isVisibleControlParameter(*cIt)) {
304                 MidiByte controllerValue = cIt->getControllerNumber();
305                 int defaultValue = cIt->getDefault();
306                 (*iIt)->setControllerValue(controllerValue, defaultValue);
307             }
308         }
309     }
310 }
311 
312 void
clearBankList()313 MidiDevice::clearBankList()
314 {
315     m_bankList.clear();
316 }
317 
318 void
clearProgramList()319 MidiDevice::clearProgramList()
320 {
321     m_programList.clear();
322 }
323 
324 void
clearKeyMappingList()325 MidiDevice::clearKeyMappingList()
326 {
327     m_keyMappingList.clear();
328 }
329 
330 void
clearControlList()331 MidiDevice::clearControlList()
332 {
333     // Clear down instrument controllers first.
334     InstrumentList insList = getAllInstruments();
335     InstrumentList::iterator iIt = insList.begin();
336 
337     for(; iIt != insList.end(); ++iIt) {
338         (*iIt)->clearStaticControllers();
339     }
340 
341     m_controlList.clear();
342 }
343 
344 void
addProgram(const MidiProgram & prog)345 MidiDevice::addProgram(const MidiProgram &prog)
346 {
347     // Refuse duplicates
348     for (ProgramList::const_iterator it = m_programList.begin();
349          it != m_programList.end(); ++it) {
350         if (it->partialCompare(prog)) return;
351     }
352 
353     m_programList.push_back(prog);
354 }
355 
356 void
addBank(const MidiBank & bank)357 MidiDevice::addBank(const MidiBank &bank)
358 {
359     m_bankList.push_back(bank);
360 }
361 
362 void
setMetronome(const MidiMetronome & metronome)363 MidiDevice::setMetronome(const MidiMetronome &metronome)
364 {
365     delete m_metronome;
366     m_metronome = new MidiMetronome(metronome);
367 }
368 
369 BankList
getBanks(bool percussion) const370 MidiDevice::getBanks(bool percussion) const
371 {
372     BankList banks;
373 
374     for (BankList::const_iterator it = m_bankList.begin();
375          it != m_bankList.end(); ++it) {
376         if (it->isPercussion() == percussion) banks.push_back(*it);
377     }
378 
379     return banks;
380 }
381 
382 BankList
getBanksByMSB(bool percussion,MidiByte msb) const383 MidiDevice::getBanksByMSB(bool percussion, MidiByte msb) const
384 {
385     BankList banks;
386 
387     for (BankList::const_iterator it = m_bankList.begin();
388          it != m_bankList.end(); ++it) {
389         if (it->isPercussion() == percussion && it->getMSB() == msb)
390             banks.push_back(*it);
391     }
392 
393     return banks;
394 }
395 
396 BankList
getBanksByLSB(bool percussion,MidiByte lsb) const397 MidiDevice::getBanksByLSB(bool percussion, MidiByte lsb) const
398 {
399     BankList banks;
400 
401     for (BankList::const_iterator it = m_bankList.begin();
402          it != m_bankList.end(); ++it) {
403         if (it->isPercussion() == percussion && it->getLSB() == lsb)
404             banks.push_back(*it);
405     }
406 
407     return banks;
408 }
409 
410 const MidiBank *
getBankByName(const std::string & name) const411 MidiDevice::getBankByName(const std::string &name) const
412 {
413     for (BankList::const_iterator i = m_bankList.begin();
414          i != m_bankList.end(); ++i) {
415         if (i->getName() == name) return &(*i);
416     }
417     return nullptr;
418 }
419 
420 MidiByteList
getDistinctMSBs(bool percussion,int lsb) const421 MidiDevice::getDistinctMSBs(bool percussion, int lsb) const
422 {
423     std::set<MidiByte> msbs;
424 
425     for (BankList::const_iterator it = m_bankList.begin();
426          it != m_bankList.end(); ++it) {
427         if (it->isPercussion() == percussion &&
428             (lsb == -1 || it->getLSB() == lsb)) msbs.insert(it->getMSB());
429     }
430 
431     MidiByteList v;
432     for (std::set<MidiByte>::iterator i = msbs.begin(); i != msbs.end(); ++i) {
433         v.push_back(*i);
434     }
435 
436     return v;
437 }
438 
439 MidiByteList
getDistinctLSBs(bool percussion,int msb) const440 MidiDevice::getDistinctLSBs(bool percussion, int msb) const
441 {
442     std::set<MidiByte> lsbs;
443 
444     for (BankList::const_iterator it = m_bankList.begin();
445          it != m_bankList.end(); ++it) {
446         if (it->isPercussion() == percussion &&
447             (msb == -1 || it->getMSB() == msb)) lsbs.insert(it->getLSB());
448     }
449 
450     MidiByteList v;
451     for (std::set<MidiByte>::iterator i = lsbs.begin(); i != lsbs.end(); ++i) {
452         v.push_back(*i);
453     }
454 
455     return v;
456 }
457 
458 ProgramList
getPrograms(const MidiBank & bank) const459 MidiDevice::getPrograms(const MidiBank &bank) const
460 {
461     ProgramList programs;
462 
463     for (ProgramList::const_iterator it = m_programList.begin();
464          it != m_programList.end(); ++it) {
465         if (it->getBank().partialCompare(bank)) programs.push_back(*it);
466     }
467 
468     return programs;
469 }
470 
471 ProgramList
getPrograms0thVariation(bool percussion,const MidiBank & bank) const472 MidiDevice::getPrograms0thVariation(bool percussion, const MidiBank &bank) const
473 {
474     // If we aren't in variations mode, just use getPrograms().
475     if (m_variationType == NoVariations)
476         return getPrograms(bank);
477 
478     // Get the variation bank list for this bank
479     BankList bankList;
480     if (m_variationType == VariationFromMSB) {
481         bankList = getBanksByLSB(percussion, bank.getLSB());
482     } else {
483         bankList = getBanksByMSB(percussion, bank.getMSB());
484     }
485 
486     if (!bankList.empty()) {
487         MidiBank firstBank = bankList.front();
488         return getPrograms(firstBank);
489     }
490 
491     return ProgramList();
492 }
493 
494 std::string
getBankName(const MidiBank & bank) const495 MidiDevice::getBankName(const MidiBank &bank) const
496 {
497     for (BankList::const_iterator it = m_bankList.begin();
498          it != m_bankList.end(); ++it) {
499         if ((*it).partialCompare(bank)) return it->getName();
500     }
501     return "";
502 }
503 
504 void
addKeyMapping(const MidiKeyMapping & mapping)505 MidiDevice::addKeyMapping(const MidiKeyMapping &mapping)
506 {
507     //!!! handle dup names
508     m_keyMappingList.push_back(mapping);
509 }
510 
511 const MidiKeyMapping *
getKeyMappingByName(const std::string & name) const512 MidiDevice::getKeyMappingByName(const std::string &name) const
513 {
514     for (KeyMappingList::const_iterator i = m_keyMappingList.begin();
515          i != m_keyMappingList.end(); ++i) {
516         if (i->getName() == name) return &(*i);
517     }
518     return nullptr;
519 }
520 
521 const MidiKeyMapping *
getKeyMappingForProgram(const MidiProgram & program) const522 MidiDevice::getKeyMappingForProgram(const MidiProgram &program) const
523 {
524     ProgramList::const_iterator it;
525 
526     for (it = m_programList.begin(); it != m_programList.end(); ++it) {
527         if (it->partialCompare(program)) {
528             std::string kmn = it->getKeyMapping();
529             if (kmn == "") return nullptr;
530             return getKeyMappingByName(kmn);
531         }
532     }
533 
534     return nullptr;
535 }
536 
537 void
setKeyMappingForProgram(const MidiProgram & program,std::string mapping)538 MidiDevice::setKeyMappingForProgram(const MidiProgram &program,
539                                     std::string mapping)
540 {
541     ProgramList::iterator it;
542 
543     for (it = m_programList.begin(); it != m_programList.end(); ++it) {
544         if (it->partialCompare(program)) {
545             it->setKeyMapping(mapping);
546         }
547     }
548 }
549 
550 
551 std::string
toXmlString() const552 MidiDevice::toXmlString() const
553 {
554     std::stringstream midiDevice;
555 
556     midiDevice << "    <device id=\""  << m_id
557                << "\" name=\""         << encode(m_name)
558                << "\" direction=\""    << (m_direction == Play ?
559                                            "play" : "record")
560                << "\" variation=\""    << (m_variationType == VariationFromLSB ?
561                                            "LSB" :
562                                            m_variationType == VariationFromMSB ?
563                                            "MSB" : "")
564                << "\" connection=\""   << encode(m_userConnection)
565                << "\" type=\"midi\">"  << std::endl << std::endl;
566 
567     midiDevice << "        <librarian name=\"" << encode(m_librarian.first)
568                << "\" email=\"" << encode(m_librarian.second)
569                << "\"/>" << std::endl;
570 
571     if (m_metronome)
572     {
573         // Write out the metronome - watch the MidiBytes
574         // when using the stringstream
575         //
576         midiDevice << "        <metronome "
577                    << "instrument=\"" << m_metronome->getInstrument() << "\" "
578                    << "barpitch=\"" << (int)m_metronome->getBarPitch() << "\" "
579                    << "beatpitch=\"" << (int)m_metronome->getBeatPitch() << "\" "
580                    << "subbeatpitch=\"" << (int)m_metronome->getSubBeatPitch() << "\" "
581                    << "depth=\"" << (int)m_metronome->getDepth() << "\" "
582                    << "barvelocity=\"" << (int)m_metronome->getBarVelocity() << "\" "
583                    << "beatvelocity=\"" << (int)m_metronome->getBeatVelocity() << "\" "
584                    << "subbeatvelocity=\"" << (int)m_metronome->getSubBeatVelocity()
585                    << "\"/>"
586                    << std::endl << std::endl;
587     }
588 
589     // and now bank information
590     //
591     BankList::const_iterator it;
592     InstrumentList::const_iterator iit;
593     ProgramList::const_iterator pt;
594 
595     for (it = m_bankList.begin(); it != m_bankList.end(); ++it)
596     {
597         midiDevice << "        <bank "
598                    << "name=\"" << encode(it->getName()) << "\" "
599                    << "percussion=\"" << (it->isPercussion() ? "true" : "false") << "\" "
600                    << "msb=\"" << (int)it->getMSB() << "\" "
601                    << "lsb=\"" << (int)it->getLSB() << "\">"
602                    << std::endl;
603 
604         // Not terribly efficient
605         //
606         for (pt = m_programList.begin(); pt != m_programList.end(); ++pt)
607         {
608             if (pt->getBank().partialCompare(*it))
609             {
610                 midiDevice << "            <program "
611                            << "id=\"" << (int)pt->getProgram() << "\" "
612                            << "name=\"" << encode(pt->getName()) << "\" ";
613                 if (!pt->getKeyMapping().empty()) {
614                     midiDevice << "keymapping=\""
615                                << encode(pt->getKeyMapping()) << "\" ";
616                 }
617                 midiDevice << "/>" << std::endl;
618             }
619         }
620 
621         midiDevice << "        </bank>" << std::endl << std::endl;
622     }
623 
624     // Now controllers (before Instruments, which can depend on
625     // Controller colours)
626     //
627     midiDevice << "        <controls>" << std::endl;
628     ControlList::const_iterator cIt;
629     for (cIt = m_controlList.begin(); cIt != m_controlList.end() ; ++cIt)
630         midiDevice << cIt->toXmlString();
631     midiDevice << "        </controls>" << std::endl << std::endl;
632 
633     // Add instruments
634     //
635     for (iit = m_instruments.begin(); iit != m_instruments.end(); ++iit)
636         midiDevice << (*iit)->toXmlString();
637 
638     KeyMappingList::const_iterator kit;
639 
640     for (kit = m_keyMappingList.begin(); kit != m_keyMappingList.end(); ++kit)
641     {
642         midiDevice << "        <keymapping "
643                    << "name=\"" << encode(kit->getName()) << "\">\n";
644 
645         for (MidiKeyMapping::KeyNameMap::const_iterator nmi =
646                  kit->getMap().begin(); nmi != kit->getMap().end(); ++nmi) {
647             midiDevice << "          <key number=\"" << (int)nmi->first
648                        << "\" name=\"" << encode(nmi->second) << "\"/>\n";
649         }
650 
651         midiDevice << "        </keymapping>\n";
652     }
653 
654     midiDevice << "    </device>" << std::endl;
655 
656     return midiDevice.str();
657 }
658 
659 // Only copy across non System instruments
660 //
661 InstrumentList
getAllInstruments() const662 MidiDevice::getAllInstruments() const
663 {
664     return m_instruments;
665 }
666 
667 // Omitting special system Instruments
668 //
669 InstrumentList
getPresentationInstruments() const670 MidiDevice::getPresentationInstruments() const
671 {
672     return m_presentationInstrumentList;
673 }
674 
675 void
addInstrument(Instrument * instrument)676 MidiDevice::addInstrument(Instrument *instrument)
677 {
678     // Check / add controls to this instrument
679     // No controls are pushed when called from the contructor since they are
680     // not generated yet!
681     ControlList::const_iterator it = m_controlList.begin();
682     for (;
683          it != m_controlList.end(); ++it)
684     {
685         if (isVisibleControlParameter(*it)) {
686             int controller = (*it).getControllerNumber();
687             try {
688                 instrument->getControllerValue(controller);
689             } catch(...) {
690                 instrument->setControllerValue(controller, it->getDefault());
691             }
692         }
693     }
694 
695     m_instruments.push_back(instrument);
696     generatePresentationList();
697 }
698 
699 std::string
getProgramName(const MidiProgram & program) const700 MidiDevice::getProgramName(const MidiProgram &program) const
701 {
702     ProgramList::const_iterator it;
703 
704     for (it = m_programList.begin(); it != m_programList.end(); ++it)
705     {
706         if (it->partialCompare(program)) return it->getName();
707     }
708 
709     return std::string("");
710 }
711 
712 void
replaceBankList(const BankList & bankList)713 MidiDevice::replaceBankList(const BankList &bankList)
714 {
715     m_bankList = bankList;
716 }
717 
718 void
replaceProgramList(const ProgramList & programList)719 MidiDevice::replaceProgramList(const ProgramList &programList)
720 {
721     m_programList = programList;
722 }
723 
724 void
replaceKeyMappingList(const KeyMappingList & keyMappingList)725 MidiDevice::replaceKeyMappingList(const KeyMappingList &keyMappingList)
726 {
727     m_keyMappingList = keyMappingList;
728 }
729 
730 
731 // Merge the new bank list in without duplication
732 //
733 void
mergeBankList(const BankList & bankList)734 MidiDevice::mergeBankList(const BankList &bankList)
735 {
736     BankList::const_iterator it;
737     BankList::iterator oIt;
738     bool clash = false;
739 
740     for (it = bankList.begin(); it != bankList.end(); ++it)
741     {
742         for (oIt = m_bankList.begin(); oIt != m_bankList.end(); ++oIt)
743         {
744             if ((*it).partialCompare(*oIt))
745             {
746                 clash = true;
747                 break;
748             }
749         }
750 
751         if (clash == false)
752             addBank(*it);
753         else
754             clash = false;
755     }
756 
757 }
758 
759 void
mergeProgramList(const ProgramList & programList)760 MidiDevice::mergeProgramList(const ProgramList &programList)
761 {
762     ProgramList::const_iterator it;
763     ProgramList::iterator oIt;
764     bool clash = false;
765 
766     for (it = programList.begin(); it != programList.end(); ++it)
767     {
768         for (oIt = m_programList.begin(); oIt != m_programList.end(); ++oIt)
769         {
770             if (it->partialCompare(*oIt))
771             {
772                 clash = true;
773                 break;
774             }
775         }
776 
777         if (clash == false)
778             addProgram(*it);
779         else
780             clash = false;
781     }
782 }
783 
784 void
mergeKeyMappingList(const KeyMappingList & keyMappingList)785 MidiDevice::mergeKeyMappingList(const KeyMappingList &keyMappingList)
786 {
787     KeyMappingList::const_iterator it;
788     KeyMappingList::iterator oIt;
789     bool clash = false;
790 
791     for (it = keyMappingList.begin(); it != keyMappingList.end(); ++it)
792     {
793         for (oIt = m_keyMappingList.begin(); oIt != m_keyMappingList.end(); ++oIt)
794         {
795             if (it->getName() == oIt->getName())
796             {
797                 clash = true;
798                 break;
799             }
800         }
801 
802         if (clash == false)
803             addKeyMapping(*it);
804         else
805             clash = false;
806     }
807 }
808 
809 void
addControlParameter(const ControlParameter & con,bool propagateToInstruments)810 MidiDevice::addControlParameter(const ControlParameter &con,
811                                 bool propagateToInstruments)
812 {
813     if (isUniqueControlParameter(con)) { //Don't allow duplicates
814         m_controlList.push_back(con);
815         if (propagateToInstruments && isVisibleControlParameter(con)) {
816             addControlToInstrument(con);
817         }
818     }
819 }
820 
821 // Add controller CON at INDEX, shifting further controllers one
822 // position forwards.
823 // Used only by RemoveControlParameterCommand.
824 void
addControlParameter(const ControlParameter & con,int index,bool propagateToInstruments)825 MidiDevice::addControlParameter(const ControlParameter &con, int index,
826                                 bool propagateToInstruments)
827 {
828     ControlList controls;
829 
830     // if we're out of range just add the control
831     if (index >= (int)m_controlList.size())
832     {
833         addControlParameter(con, propagateToInstruments);
834         return;
835     }
836 
837     // Rebuild the ControlList entry by entry, placing CON at INDEX.
838     // For entry INDEX we do two push_back's, for other entries we do
839     // one.
840     for (int i = 0; i < (int)m_controlList.size(); ++i)
841     {
842         if (index == i) {
843             controls.push_back(con);
844             // !!! This seems to do more than we need, since we
845             // discard the original m_controlList.
846             addControlParameter(con, propagateToInstruments);
847         }
848         controls.push_back(m_controlList[i]);
849     }
850 
851     // Assign the ControlList we just made.
852     m_controlList = controls;
853 }
854 
855 
856 bool
removeControlParameter(int index)857 MidiDevice::removeControlParameter(int index)
858 {
859     ControlList::iterator it = m_controlList.begin();
860     int i = 0;
861 
862     for (; it != m_controlList.end(); ++it)
863     {
864         if (index == i)
865         {
866             removeControlFromInstrument(*it);
867             m_controlList.erase(it);
868             return true;
869         }
870         i++;
871     }
872 
873     return false;
874 }
875 
876 bool
modifyControlParameter(const ControlParameter & con,int index)877 MidiDevice::modifyControlParameter(const ControlParameter &con, int index)
878 {
879     if (index < 0 || index > (int)m_controlList.size()) return false;
880     removeControlFromInstrument(m_controlList[index]);
881     m_controlList[index] = con;
882     addControlToInstrument(con);
883     return true;
884 }
885 
886 void
replaceControlParameters(const ControlList & con)887 MidiDevice::replaceControlParameters(const ControlList &con)
888 {
889     // Clear down instrument controllers in preparation for replace.
890     InstrumentList insList = getAllInstruments();
891     InstrumentList::iterator iIt = insList.begin();
892 
893     for(; iIt != insList.end(); ++iIt) {
894         (*iIt)->clearStaticControllers();
895     }
896 
897     // Clear the Device control list
898     m_controlList.clear();
899 
900     // Now add the controllers to the device,
901     ControlList::const_iterator cIt = con.begin();
902     for(; cIt != con.end(); ++cIt) {
903         addControlParameter(*cIt, true);
904     }
905 }
906 
907 #if 0
908 // Conform instrument controllers to a new setup.
909 void
910 MidiDevice::
911 conformInstrumentControllers(void)
912 {
913     InstrumentList insList = getAllInstruments();
914 
915     // Treat each instrument
916     for(InstrumentList::iterator iIt = insList.begin();
917         iIt != insList.end();
918         ++iIt) {
919         // Get this instrument's static controllers.  As a seperate
920         // copy, so it's not munged when we erase controllers.
921         StaticControllers staticControllers =
922             (*iIt)->getStaticControllers();
923 
924         for (StaticControllers::iterator it = staticControllers.begin();
925              it != staticControllers.end();
926              ++it) {
927             MidiByte controllerNumber = it->first;
928 
929             const ControlParameter * con =
930                 findControlParameter(Rosegarden::Controller::EventType,
931                         controllerNumber);
932             if (!con) {
933                 // It doesn't exist in device, so remove it from
934                 // instrument.
935                 (*iIt)->removeStaticController(controllerNumber);
936             }
937             else if ((*iIt)->getControllerNumber(controllerNumber) == 0) {
938                 // Controller value probably has an old default value,
939                 // so set it to the new default.
940                 MidiByte value = con->getDefault();
941                 (*iIt)->setControllerValue(controllerNumber, value);
942             }
943         }
944     }
945 }
946 #endif
947 
948 // Check to see if passed ControlParameter is unique.  Either the
949 // type must be unique or in the case of Controller::EventType the
950 // ControllerValue must be unique.
951 //
952 // Controllers (Control type)
953 //
954 //
955 bool
isUniqueControlParameter(const ControlParameter & con) const956 MidiDevice::isUniqueControlParameter(const ControlParameter &con) const
957 {
958     return
959         findControlParameter(con.getType(), con.getControllerNumber()) == nullptr;
960 }
961 
962 const ControlParameter *
963 MidiDevice::
findControlParameter(std::string type,MidiByte controllerNumber) const964 findControlParameter(std::string type, MidiByte controllerNumber) const
965 {
966     ControlList::const_iterator it = m_controlList.begin();
967 
968     for (; it != m_controlList.end(); ++it)
969     {
970         if (it->getType() == type)
971         {
972             if (it->getType() == Rosegarden::Controller::EventType &&
973                 it->getControllerNumber() != controllerNumber)
974                 { continue; }
975             return &*it;
976         }
977     }
978     return nullptr;
979 }
980 
981 bool
isVisibleControlParameter(const ControlParameter & con) const982 MidiDevice::isVisibleControlParameter(const ControlParameter &con) const
983 {
984     // ??? Inline this and get rid of it.  It is a one-liner that is only
985     //     used internally.
986 
987     return (con.getIPBPosition() > -1);
988 }
989 
990 bool
isVisibleControlParameter(MidiByte controlNumber) const991 MidiDevice::isVisibleControlParameter(MidiByte controlNumber) const
992 {
993     // For each CC...
994     for (const ControlParameter &controlParameter : m_controlList)
995     {
996         // Not a CC?  Skip.
997         if (controlParameter.getType() != Controller::EventType)
998             continue;
999 
1000         // If we found it...
1001         if (controlParameter.getControllerNumber() == controlNumber)
1002             return (controlParameter.getIPBPosition() > -1 );
1003     }
1004 
1005     return false;
1006 }
1007 
1008 void
addControlToInstrument(const ControlParameter & con)1009 MidiDevice::addControlToInstrument(const ControlParameter &con)
1010 {
1011     if (!isVisibleControlParameter(con)) {
1012         return;
1013     }
1014 
1015     // Run through all of this devices instruments and add default controls and
1016     // values to them.
1017     InstrumentList insList = getAllInstruments();
1018     InstrumentList::iterator iIt = insList.begin();
1019 
1020     for(; iIt != insList.end(); ++iIt) {
1021         MidiByte controllerNumber = con.getControllerNumber();
1022         MidiByte controllerValue = con.getDefault();
1023         (*iIt)->setControllerValue(controllerNumber, controllerValue);
1024     }
1025 }
1026 
1027 void
removeControlFromInstrument(const ControlParameter & controlParameter)1028 MidiDevice::removeControlFromInstrument(
1029         const ControlParameter &controlParameter)
1030 {
1031     InstrumentList instrumentList = getAllInstruments();
1032 
1033     for (InstrumentList::iterator instrumentIter = instrumentList.begin();
1034          instrumentIter != instrumentList.end();
1035          ++instrumentIter) {
1036         (*instrumentIter)->removeStaticController(
1037                 controlParameter.getControllerNumber());
1038     }
1039 }
1040 
1041 ControlList
getIPBControlParameters() const1042 MidiDevice::getIPBControlParameters() const
1043 {
1044     ControlList retList;
1045 
1046     for (ControlList::const_iterator it = m_controlList.begin();
1047          it != m_controlList.end(); ++it)
1048     {
1049         if (it->getIPBPosition() != -1 &&
1050             it->getControllerNumber() != MIDI_CONTROLLER_VOLUME)
1051             retList.push_back(*it);
1052     }
1053 
1054     return retList;
1055 }
1056 
1057 ControlParameter *
getControlParameter(int index)1058 MidiDevice::getControlParameter(int index)
1059 {
1060     if (index >= 0 && ((unsigned int)index) < (unsigned int)m_controlList.size())
1061         return &m_controlList[index];
1062 
1063     return nullptr;
1064 }
1065 
1066 const ControlParameter *
getControlParameter(int index) const1067 MidiDevice::getControlParameter(int index) const
1068 {
1069     return ((MidiDevice *)this)->getControlParameter(index);
1070 }
1071 
1072 ControlParameter *
getControlParameter(const std::string & type,Rosegarden::MidiByte controllerValue)1073 MidiDevice::getControlParameter(const std::string &type, Rosegarden::MidiByte controllerValue)
1074 {
1075     ControlList::iterator it = m_controlList.begin();
1076 
1077     for (; it != m_controlList.end(); ++it)
1078     {
1079         if (it->getType() == type)
1080         {
1081             // Return matched on type for most events
1082             //
1083             if (type != Rosegarden::Controller::EventType)
1084                 return &*it;
1085 
1086             // Also match controller value for Controller events
1087             //
1088             if (it->getControllerNumber() == controllerValue)
1089                 return  &*it;
1090         }
1091     }
1092 
1093     return nullptr;
1094 }
1095 
1096 const ControlParameter *
getControlParameter(const std::string & type,Rosegarden::MidiByte controllerValue) const1097 MidiDevice::getControlParameter(const std::string &type, Rosegarden::MidiByte controllerValue) const
1098 {
1099     return ((MidiDevice *)this)->getControlParameter(type, controllerValue);
1100 }
1101 
1102 }
1103 
1104