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