1 //=============================================================================
2 // MuseScore
3 // Music Composition & Notation
4 //
5 // Copyright (C) 2002-2011 Werner Schweer
6 //
7 // This program is free software; you can redistribute it and/or modify
8 // it under the terms of the GNU General Public License version 2
9 // as published by the Free Software Foundation and appearing in
10 // the file LICENCE.GPL
11 //=============================================================================
12
13 #include "instrtemplate.h"
14 #include "bracket.h"
15 #include "drumset.h"
16 #include "stafftype.h"
17 #include "style.h"
18 #include "sym.h"
19 #include "stringdata.h"
20 #include "scoreOrder.h"
21 #include "utils.h"
22 #include "xml.h"
23
24 namespace Ms {
25
26 QList<InstrumentGroup*> instrumentGroups;
27 QList<MidiArticulation> articulation; // global articulations
28 QList<InstrumentGenre*> instrumentGenres;
29 QList<InstrumentFamily*> instrumentFamilies;
30
31 //---------------------------------------------------------
32 // searchInstrumentGenre
33 //---------------------------------------------------------
34
searchInstrumentGenre(const QString & genre)35 static InstrumentGenre * searchInstrumentGenre(const QString& genre)
36 {
37 for(InstrumentGenre* ig : qAsConst(instrumentGenres)) {
38 if (ig->id == genre)
39 return ig;
40 }
41 return nullptr;
42 }
43
44 //---------------------------------------------------------
45 // searchInstrumentFamily
46 //---------------------------------------------------------
47
searchInstrumentFamily(const QString & name)48 static InstrumentFamily * searchInstrumentFamily(const QString& name)
49 {
50 for(InstrumentFamily* fam : qAsConst(instrumentFamilies)) {
51 if (fam->id == name)
52 return fam;
53 }
54 return nullptr;
55 }
56
57 //---------------------------------------------------------
58 // searchInstrumentGroup
59 //---------------------------------------------------------
60
searchInstrumentGroup(const QString & name)61 InstrumentGroup* searchInstrumentGroup(const QString& name)
62 {
63 for(InstrumentGroup* g : qAsConst(instrumentGroups)) {
64 if (g->id == name)
65 return g;
66 }
67 return nullptr;
68 }
69
70 //---------------------------------------------------------
71 // searchArticulation
72 //---------------------------------------------------------
73
searchArticulation(const QString & name)74 static MidiArticulation searchArticulation(const QString& name)
75 {
76 for(MidiArticulation a : qAsConst(articulation)) {
77 if (a.name == name)
78 return a;
79 }
80 return MidiArticulation();
81 }
82
83 //---------------------------------------------------------
84 // readStaffIdx
85 //---------------------------------------------------------
86
readStaffIdx(XmlReader & e)87 static int readStaffIdx(XmlReader& e)
88 {
89 int idx = e.intAttribute("staff", 1) - 1;
90 if (idx >= MAX_STAVES)
91 idx = MAX_STAVES-1;
92 if (idx < 0)
93 idx = 0;
94 return idx;
95 }
96
97 //---------------------------------------------------------
98 // read InstrumentGroup
99 //---------------------------------------------------------
100
read(XmlReader & e)101 void InstrumentGroup::read(XmlReader& e)
102 {
103 id = e.attribute("id");
104 name = qApp->translate("InstrumentsXML", e.attribute("name").toUtf8().data());
105 extended = e.intAttribute("extended", 0);
106
107 while (e.readNextStartElement()) {
108 const QStringRef& tag(e.name());
109 if (tag == "instrument" || tag == "Instrument") {
110 QString sid = e.attribute("id");
111 InstrumentTemplate* t = searchTemplate(sid);
112 if (t == 0) {
113 t = new InstrumentTemplate;
114 t->articulation.append(articulation); // init with global articulation
115 instrumentTemplates.append(t);
116 }
117 t->read(e);
118 }
119 else if (tag == "ref") {
120 InstrumentTemplate* ttt = searchTemplate(e.readElementText());
121 if (ttt) {
122 InstrumentTemplate* t = new InstrumentTemplate(*ttt);
123 instrumentTemplates.append(t);
124 }
125 else
126 qDebug("instrument reference not found <%s>", e.text().toUtf8().data());
127 }
128 else if (tag == "name")
129 name = qApp->translate("InstrumentsXML", e.readElementText().toUtf8().data());
130 else if (tag == "extended")
131 extended = e.readInt();
132 else
133 e.unknown();
134 }
135 if (id.isEmpty())
136 id = name.toLower().replace(" ", "-");
137 }
138
139 //---------------------------------------------------------
140 // clear InstrumentGroup
141 //---------------------------------------------------------
142
clear()143 void InstrumentGroup::clear()
144 {
145 qDeleteAll(instrumentTemplates);
146 instrumentTemplates.clear();
147 }
148
149 //---------------------------------------------------------
150 // InstrumentTemplate
151 //---------------------------------------------------------
152
InstrumentTemplate()153 InstrumentTemplate::InstrumentTemplate()
154 {
155 staves = 1;
156 minPitchA = 0;
157 maxPitchA = 127;
158 minPitchP = 0;
159 maxPitchP = 127;
160 staffGroup = StaffGroup::STANDARD;
161 staffTypePreset = 0;
162 useDrumset = false;
163 drumset = 0;
164 extended = false;
165 singleNoteDynamics = true;
166 family = nullptr;
167
168 for (int i = 0; i < MAX_STAVES; ++i) {
169 clefTypes[i]._concertClef = ClefType::G;
170 clefTypes[i]._transposingClef = ClefType::G;
171 staffLines[i] = 5;
172 smallStaff[i] = false;
173 bracket[i] = BracketType::NO_BRACKET;
174 bracketSpan[i] = 0;
175 barlineSpan[i] = false;
176 }
177 transpose.diatonic = 0;
178 transpose.chromatic = 0;
179 }
180
InstrumentTemplate(const InstrumentTemplate & t)181 InstrumentTemplate::InstrumentTemplate(const InstrumentTemplate& t)
182 {
183 init(t);
184 }
185
186 //---------------------------------------------------------
187 // init
188 //---------------------------------------------------------
189
init(const InstrumentTemplate & t)190 void InstrumentTemplate::init(const InstrumentTemplate& t)
191 {
192 longNames = t.longNames;
193 shortNames = t.shortNames;
194 musicXMLid = t.musicXMLid;
195 staves = t.staves;
196 extended = t.extended;
197
198 for (int i = 0; i < MAX_STAVES; ++i) {
199 clefTypes[i] = t.clefTypes[i];
200 staffLines[i] = t.staffLines[i];
201 smallStaff[i] = t.smallStaff[i];
202 bracket[i] = t.bracket[i];
203 bracketSpan[i] = t.bracketSpan[i];
204 barlineSpan[i] = t.barlineSpan[i];
205 }
206 minPitchA = t.minPitchA;
207 maxPitchA = t.maxPitchA;
208 minPitchP = t.minPitchP;
209 maxPitchP = t.maxPitchP;
210 transpose = t.transpose;
211 staffGroup = t.staffGroup;
212 staffTypePreset = t.staffTypePreset;
213 useDrumset = t.useDrumset;
214 if (t.drumset)
215 drumset = new Drumset(*t.drumset);
216 else
217 drumset = 0;
218 stringData = t.stringData;
219 midiActions = t.midiActions;
220 channel = t.channel;
221 family = t.family;
222 singleNoteDynamics = t.singleNoteDynamics;
223 }
224
~InstrumentTemplate()225 InstrumentTemplate::~InstrumentTemplate()
226 {
227 delete drumset;
228 }
229
230 //---------------------------------------------------------
231 // write
232 //---------------------------------------------------------
233
write(XmlWriter & xml) const234 void InstrumentTemplate::write(XmlWriter& xml) const
235 {
236 xml.stag(QString("Instrument id=\"%1\"").arg(id));
237 longNames.write(xml, "longName");
238 shortNames.write(xml, "shortName");
239
240 if (longNames.size() > 1)
241 xml.tag("trackName", trackName);
242 xml.tag("description", description);
243 xml.tag("musicXMLid", musicXMLid);
244 if (extended)
245 xml.tag("extended", extended);
246 stringData.write(xml);
247 if (staves > 1)
248 xml.tag("staves", staves);
249 for (int i = 0; i < staves; ++i) {
250 if (clefTypes[i]._concertClef == clefTypes[i]._transposingClef) {
251 QString tag = ClefInfo::tag(clefTypes[i]._concertClef);
252 if (i)
253 xml.tag(QString("clef staff=\"%1\"").arg(i+1), tag);
254 else
255 xml.tag("clef", tag);
256 }
257 else {
258 QString tag1 = ClefInfo::tag(clefTypes[i]._concertClef);
259 QString tag2 = ClefInfo::tag(clefTypes[i]._transposingClef);
260 if (i) {
261 xml.tag(QString("concertClef staff=\"%1\"").arg(i+1), tag1);
262 xml.tag(QString("transposingClef staff=\"%1\"").arg(i+1), tag2);
263 }
264 else {
265 xml.tag("concertClef", tag1);
266 xml.tag("transposingClef", tag2);
267 }
268 }
269 if (staffLines[i] != 5) {
270 if (i)
271 xml.tag(QString("stafflines staff=\"%1\"").arg(i+1), staffLines[i]);
272 else
273 xml.tag("stafflines", staffLines[i]);
274 }
275 if (smallStaff[i]) {
276 if (i)
277 xml.tag(QString("smallStaff staff=\"%1\"").arg(i+1), smallStaff[i]);
278 else
279 xml.tag("smallStaff", smallStaff[i]);
280 }
281
282 if (bracket[i] != BracketType::NO_BRACKET) {
283 if (i)
284 xml.tag(QString("bracket staff=\"%1\"").arg(i+1), int(bracket[i]));
285 else
286 xml.tag("bracket", int(bracket[i]));
287 }
288 if (bracketSpan[i] != 0) {
289 if (i)
290 xml.tag(QString("bracketSpan staff=\"%1\"").arg(i+1), bracketSpan[i]);
291 else
292 xml.tag("bracketSpan", bracketSpan[i]);
293 }
294 if (barlineSpan[i]) {
295 if (i)
296 xml.tag(QString("barlineSpan staff=\"%1\"").arg(i+1), barlineSpan[i]);
297 else
298 xml.tag("barlineSpan", barlineSpan[i]);
299 }
300 }
301 if (minPitchA != 0 || maxPitchA != 127)
302 xml.tag("aPitchRange", QString("%1-%2").arg(int(minPitchA)).arg(int(maxPitchA)));
303 if (minPitchP != 0 || maxPitchP != 127)
304 xml.tag("pPitchRange", QString("%1-%2").arg(int(minPitchP)).arg(int(maxPitchP)));
305 if (transpose.diatonic)
306 xml.tag("transposeDiatonic", transpose.diatonic);
307 if (transpose.chromatic)
308 xml.tag("transposeChromatic", transpose.chromatic);
309 if (useDrumset)
310 xml.tag("drumset", int(useDrumset));
311 if (drumset)
312 drumset->save(xml);
313
314 if (!singleNoteDynamics) // default is true
315 xml.tag("singleNoteDynamics", singleNoteDynamics);
316
317 for (const NamedEventList& a : midiActions)
318 a.write(xml, "MidiAction");
319 for (const Channel& a : channel)
320 a.write(xml, nullptr);
321 for (const MidiArticulation& ma : articulation) {
322 bool isGlobal = false;
323 for (const MidiArticulation& ga : qAsConst(Ms::articulation)) {
324 if (ma == ga) {
325 isGlobal = true;
326 break;
327 }
328 }
329 if (!isGlobal)
330 ma.write(xml);
331 }
332 if (!family)
333 xml.tag("family", family->id);
334 xml.etag();
335 }
336
337 //---------------------------------------------------------
338 // write1
339 // output only translatable names
340 //---------------------------------------------------------
341
write1(XmlWriter & xml) const342 void InstrumentTemplate::write1(XmlWriter& xml) const
343 {
344 xml.stag(QString("Instrument id=\"%1\"").arg(id));
345 longNames.write(xml, "longName");
346 shortNames.write(xml, "shortName");
347 if (longNames.size() > 1)
348 xml.tag("trackName", trackName);
349 xml.tag("description", description);
350 xml.etag();
351 }
352
353 //---------------------------------------------------------
354 // read
355 //---------------------------------------------------------
356
read(XmlReader & e)357 void InstrumentTemplate::read(XmlReader& e)
358 {
359 id = e.attribute("id");
360 while (e.readNextStartElement()) {
361 const QStringRef& tag(e.name());
362
363 if (tag == "longName" || tag == "name") { // "name" is obsolete
364 int pos = e.intAttribute("pos", 0);
365 for (QList<StaffName>::iterator i = longNames.begin(); i != longNames.end(); ++i) {
366 if ((*i).pos() == pos) {
367 longNames.erase(i);
368 break;
369 }
370 }
371 longNames.append(StaffName(qApp->translate("InstrumentsXML", e.readElementText().toUtf8().data()), pos));
372 }
373 else if (tag == "shortName" || tag == "short-name") { // "short-name" is obsolete
374 int pos = e.intAttribute("pos", 0);
375 for (QList<StaffName>::iterator i = shortNames.begin(); i != shortNames.end(); ++i) {
376 if ((*i).pos() == pos) {
377 shortNames.erase(i);
378 break;
379 }
380 }
381 shortNames.append(StaffName(qApp->translate("InstrumentsXML", e.readElementText().toUtf8().data()), pos));
382 }
383 else if (tag == "trackName")
384 trackName = qApp->translate("InstrumentsXML", e.readElementText().toUtf8().data());
385 else if (tag == "description")
386 description = e.readElementText();
387 else if (tag == "extended")
388 extended = e.readInt();
389 else if (tag == "staves") {
390 staves = e.readInt();
391 bracketSpan[0] = staves;
392 // for (int i = 0; i < staves-1; ++i)
393 // barlineSpan[i] = true;
394 }
395 else if (tag == "clef") { // sets both transposing and concert clef
396 int idx = readStaffIdx(e);
397 QString val(e.readElementText());
398 bool ok;
399 int i = val.toInt(&ok);
400 ClefType ct = ok ? ClefType(i) : Clef::clefType(val);
401 clefTypes[idx]._concertClef = ct;
402 clefTypes[idx]._transposingClef = ct;
403 }
404 else if (tag == "concertClef") {
405 int idx = readStaffIdx(e);
406 QString val(e.readElementText());
407 bool ok;
408 int i = val.toInt(&ok);
409 clefTypes[idx]._concertClef = ok ? ClefType(i) : Clef::clefType(val);
410 }
411 else if (tag == "transposingClef") {
412 int idx = readStaffIdx(e);
413 QString val(e.readElementText());
414 bool ok;
415 int i = val.toInt(&ok);
416 clefTypes[idx]._transposingClef = ok ? ClefType(i) : Clef::clefType(val);
417 }
418 else if (tag == "stafflines") {
419 int idx = readStaffIdx(e);
420 staffLines[idx] = e.readInt();
421 }
422 else if (tag == "smallStaff") {
423 int idx = readStaffIdx(e);
424 smallStaff[idx] = e.readInt();
425 }
426 else if (tag == "bracket") {
427 int idx = readStaffIdx(e);
428 bracket[idx] = BracketType(e.readInt());
429 }
430 else if (tag == "bracketSpan") {
431 int idx = readStaffIdx(e);
432 bracketSpan[idx] = e.readInt();
433 }
434 else if (tag == "barlineSpan") {
435 int idx = readStaffIdx(e);
436 int span = e.readInt();
437 for (int i = 0; i < span-1; ++i)
438 barlineSpan[idx+i] = true;
439 }
440 else if (tag == "aPitchRange")
441 setPitchRange(e.readElementText(), &minPitchA, &maxPitchA);
442 else if (tag == "pPitchRange")
443 setPitchRange(e.readElementText(), &minPitchP, &maxPitchP);
444 else if (tag == "transposition") { // obsolete
445 int i = e.readInt();
446 transpose.chromatic = i;
447 transpose.diatonic = chromatic2diatonic(i);
448 }
449 else if (tag == "transposeChromatic")
450 transpose.chromatic = e.readInt();
451 else if (tag == "transposeDiatonic")
452 transpose.diatonic = e.readInt();
453 else if (tag == "StringData")
454 stringData.read(e);
455 else if (tag == "drumset")
456 useDrumset = e.readInt();
457 else if (tag == "Drum") {
458 // if we see one of this tags, a custom drumset will
459 // be created
460 if (drumset == 0) {
461 drumset = new Drumset(*smDrumset);
462 drumset->clear();
463 }
464 drumset->load(e);
465 }
466 else if (tag == "MidiAction") {
467 NamedEventList a;
468 a.read(e);
469 midiActions.append(a);
470 }
471 else if (tag == "Channel" || tag == "channel") {
472 Channel a;
473 a.read(e, nullptr);
474 channel.append(a);
475 }
476 else if (tag == "Articulation") {
477 MidiArticulation a;
478 a.read(e);
479 int n = articulation.size();
480 int i;
481 for(i = 0; i < n; ++i) {
482 if (articulation[i].name == a.name) {
483 articulation[i] = a;
484 break;
485 }
486 }
487 if (i == n)
488 articulation.append(a);
489 }
490 else if (tag == "stafftype") {
491 int staffIdx = readStaffIdx(e);
492 QString xmlPresetName = e.attribute("staffTypePreset", "");
493 QString stfGroup = e.readElementText();
494 if (stfGroup == "percussion")
495 staffGroup = StaffGroup::PERCUSSION;
496 else if (stfGroup == "tablature")
497 staffGroup = StaffGroup::TAB;
498 else
499 staffGroup = StaffGroup::STANDARD;
500 staffTypePreset = 0;
501 if (!xmlPresetName.isEmpty())
502 staffTypePreset = StaffType::presetFromXmlName(xmlPresetName);
503 if (!staffTypePreset || staffTypePreset->group() != staffGroup)
504 staffTypePreset = StaffType::getDefaultPreset(staffGroup);
505 if (staffTypePreset)
506 staffLines[staffIdx] = staffTypePreset->lines();
507 }
508 else if (tag == "init") {
509 QString val(e.readElementText());
510 InstrumentTemplate* ttt = searchTemplate(val);
511 if (ttt)
512 init(*ttt);
513 else
514 qDebug("InstrumentTemplate:: init instrument <%s> not found", qPrintable(val));
515 }
516 else if (tag == "musicXMLid") {
517 musicXMLid = e.readElementText();
518 }
519 else if (tag == "family") {
520 family = searchInstrumentFamily(e.readElementText());
521 }
522 else if (tag == "genre") {
523 QString val(e.readElementText());
524 linkGenre(val);
525 }
526 else if (tag == "singleNoteDynamics")
527 singleNoteDynamics = e.readBool();
528 else
529 e.unknown();
530 }
531 if (channel.empty()) {
532 Channel a;
533 a.setChorus(0);
534 a.setReverb(0);
535 a.setName(Channel::DEFAULT_NAME);
536 a.setProgram(0);
537 a.setBank(0);
538 a.setVolume(90);
539 a.setPan(0);
540 channel.append(a);
541 }
542 if (useDrumset) {
543 if (channel[0].bank() == 0 && channel[0].synti().toLower() != "zerberus")
544 channel[0].setBank(128);
545 }
546 if (trackName.isEmpty() && !longNames.isEmpty())
547 trackName = longNames[0].name();
548 if (description.isEmpty() && !longNames.isEmpty())
549 description = longNames[0].name();
550 if (id.isEmpty())
551 id = trackName.toLower().replace(" ", "-");
552 if (staves == 0)
553 qDebug(" 2Instrument: staves == 0 <%s>", qPrintable(id));
554 }
555
556
557 //---------------------------------------------------------
558 // setPitchRange
559 //---------------------------------------------------------
560
setPitchRange(const QString & s,char * a,char * b) const561 void InstrumentTemplate::setPitchRange(const QString& s, char* a, char* b) const
562 {
563 QStringList sl = s.split("-");
564 if (sl.size() != 2) {
565 *a = 0;
566 *b = 127;
567 return;
568 }
569 *a = sl[0].toInt();
570 *b = sl[1].toInt();
571 }
572
573 //---------------------------------------------------------
574 // saveInstrumentTemplates
575 //---------------------------------------------------------
576
saveInstrumentTemplates(const QString & instrTemplates)577 bool saveInstrumentTemplates(const QString& instrTemplates)
578 {
579 QFile qf(instrTemplates);
580 if (!qf.open(QIODevice::WriteOnly)) {
581 qDebug("cannot save instrument templates at <%s>", qPrintable(instrTemplates));
582 return false;
583 }
584 XmlWriter xml(0, &qf);
585 xml << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
586 xml.stag("museScore");
587 foreach(const InstrumentGenre* genre, instrumentGenres)
588 genre->write(xml);
589 xml << "\n";
590 foreach(const InstrumentFamily* fam, instrumentFamilies)
591 fam->write(xml);
592 xml << "\n";
593 foreach(const MidiArticulation& a, articulation)
594 a.write(xml);
595 xml << "\n";
596 foreach(InstrumentGroup* group, instrumentGroups) {
597 xml.stag(QString("InstrumentGroup id=\"%1\"").arg(group->id));
598 xml.tag("name", group->name);
599 if (group->extended)
600 xml.tag("extended", group->extended);
601 for (InstrumentTemplate* it : qAsConst(group->instrumentTemplates)) {
602 it->write(xml);
603 xml << "\n";
604 }
605 xml.etag();
606 xml << "\n";
607 }
608 xml.etag();
609 qf.close();
610 return true;
611 }
612
613 //---------------------------------------------------------
614 // saveInstrumentTemplates1
615 //---------------------------------------------------------
616
saveInstrumentTemplates1(const QString & instrTemplates)617 bool saveInstrumentTemplates1(const QString& instrTemplates)
618 {
619 QFile qf(instrTemplates);
620 if (!qf.open(QIODevice::WriteOnly)) {
621 qDebug("cannot save instrument templates at <%s>", qPrintable(instrTemplates));
622 return false;
623 }
624 XmlWriter xml(0, &qf);
625 xml << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
626 xml.stag("museScore");
627 foreach(const InstrumentGenre* genre, instrumentGenres)
628 genre->write1(xml);
629 foreach(const InstrumentFamily* fam, instrumentFamilies)
630 fam->write1(xml);
631 xml << "\n";
632 foreach(InstrumentGroup* group, instrumentGroups) {
633 xml.stag(QString("InstrumentGroup id=\"%1\"").arg(group->id));
634 xml.tag("name", group->name);
635 for (InstrumentTemplate* it : qAsConst(group->instrumentTemplates)) {
636 it->write1(xml);
637 xml << "\n";
638 }
639 xml.etag();
640 xml << "\n";
641 }
642 xml.etag();
643 qf.close();
644 return true;
645 }
646
647 //---------------------------------------------------------
648 // clearInstrumentTemplates
649 //---------------------------------------------------------
650
clearInstrumentTemplates()651 void clearInstrumentTemplates()
652 {
653 for (InstrumentGroup* g : qAsConst(instrumentGroups))
654 g->clear();
655 qDeleteAll(instrumentGroups);
656 instrumentGroups.clear();
657 qDeleteAll(instrumentGenres);
658 instrumentGenres.clear();
659 qDeleteAll(instrumentFamilies);
660 instrumentFamilies.clear();
661 articulation.clear();
662 }
663
664 //---------------------------------------------------------
665 // loadInstrumentTemplates
666 //---------------------------------------------------------
667
loadInstrumentTemplates(const QString & instrTemplates)668 bool loadInstrumentTemplates(const QString& instrTemplates)
669 {
670 QFile qf(instrTemplates);
671 if (!qf.open(QIODevice::Text | QIODevice::ReadOnly)) {
672 qDebug("cannot load instrument templates at <%s>", qPrintable(instrTemplates));
673 return false;
674 }
675
676 XmlReader e(&qf);
677 while (e.readNextStartElement()) {
678 if (e.name() == "museScore") {
679 while (e.readNextStartElement()) {
680 const QStringRef& tag(e.name());
681 if (tag == "instrument-group" || tag == "InstrumentGroup") {
682 QString idGroup(e.attribute("id"));
683 InstrumentGroup* group = searchInstrumentGroup(idGroup);
684 if (group == 0) {
685 group = new InstrumentGroup;
686 instrumentGroups.append(group);
687 }
688 group->read(e);
689 }
690 else if (tag == "Articulation") {
691 // read global articulation
692 QString name(e.attribute("name"));
693 MidiArticulation a = searchArticulation(name);
694 a.read(e);
695 articulation.append(a);
696 }
697 else if (tag == "Genre") {
698 QString idGenre(e.attribute("id"));
699 InstrumentGenre* genre = searchInstrumentGenre(idGenre);
700 if (!genre) {
701 genre = new InstrumentGenre;
702 instrumentGenres.append(genre);
703 }
704 genre->read(e);
705 }
706 else if (tag == "Family") {
707 QString idFamily(e.attribute("id"));
708 InstrumentFamily* fam = searchInstrumentFamily(idFamily);
709 if (!fam) {
710 fam = new InstrumentFamily;
711 instrumentFamilies.append(fam);
712 }
713 fam->read(e);
714 }
715 else
716 e.unknown();
717 }
718 }
719 }
720 // saveInstrumentTemplates1("/home/ws/mops.xml");
721 return true;
722 }
723
724 //---------------------------------------------------------
725 // searchTemplate
726 //---------------------------------------------------------
727
searchTemplate(const QString & name)728 InstrumentTemplate* searchTemplate(const QString& name)
729 {
730 for (InstrumentGroup* g : qAsConst(instrumentGroups)) {
731 for (InstrumentTemplate* it : qAsConst(g->instrumentTemplates)) {
732 if (it->id == name)
733 return it;
734 }
735 }
736 return 0;
737 }
738
739 //---------------------------------------------------------
740 // searchTemplateForMusicXMLid
741 //---------------------------------------------------------
742
searchTemplateForMusicXmlId(const QString & mxmlId)743 InstrumentTemplate* searchTemplateForMusicXmlId(const QString& mxmlId)
744 {
745 for (InstrumentGroup* g : qAsConst(instrumentGroups)) {
746 for (InstrumentTemplate* it : qAsConst(g->instrumentTemplates)) {
747 if (it->musicXMLid == mxmlId)
748 return it;
749 }
750 }
751 return 0;
752 }
753
searchTemplateForInstrNameList(const QList<QString> & nameList)754 InstrumentTemplate* searchTemplateForInstrNameList(const QList<QString>& nameList)
755 {
756 for (InstrumentGroup* g : qAsConst(instrumentGroups)) {
757 for (InstrumentTemplate* it : qAsConst(g->instrumentTemplates)) {
758 for (const QString& name : nameList) {
759 if (it->trackName == name ||
760 it->longNames.contains(StaffName(name)) ||
761 it->shortNames.contains(StaffName(name)))
762 return it;
763 }
764 }
765 }
766 return nullptr;
767 }
768
searchTemplateForMidiProgram(int midiProgram,const bool useDrumSet)769 InstrumentTemplate* searchTemplateForMidiProgram(int midiProgram, const bool useDrumSet)
770 {
771 for (InstrumentGroup* g : qAsConst(instrumentGroups)) {
772 for (InstrumentTemplate* it : qAsConst(g->instrumentTemplates)) {
773 if (it->channel.empty() || it->useDrumset != useDrumSet)
774 continue;
775
776 if (it->channel[0].program() == midiProgram)
777 return it;
778 }
779 }
780 return 0;
781 }
782
guessTemplateByNameData(const QList<QString> & nameDataList)783 InstrumentTemplate* guessTemplateByNameData(const QList<QString>& nameDataList)
784 {
785 for (InstrumentGroup* g : qAsConst(instrumentGroups)) {
786 for (InstrumentTemplate* it : qAsConst(g->instrumentTemplates)) {
787 for (const QString& name : nameDataList) {
788 if (name.contains(it->trackName, Qt::CaseInsensitive) ||
789 name.contains(it->longNames.value(0).name(), Qt::CaseInsensitive) ||
790 name.contains(it->shortNames.value(0).name(), Qt::CaseInsensitive)) {
791 return it;
792 }
793 }
794 }
795 }
796
797 for (const QString& name : nameDataList) {
798 if (name.contains("drum", Qt::CaseInsensitive))
799 return searchTemplate("drumset");
800
801 if (name.contains("piano", Qt::CaseInsensitive))
802 return searchTemplate("piano");
803 }
804
805 return nullptr;
806 }
807
808 //---------------------------------------------------------
809 // searchTemplateIndexForTrackName
810 //---------------------------------------------------------
811
searchTemplateIndexForTrackName(const QString & trackName)812 InstrumentIndex searchTemplateIndexForTrackName(const QString& trackName)
813 {
814 int instIndex = 0;
815 int grpIndex = 0;
816 for (InstrumentGroup* g : qAsConst(instrumentGroups)) {
817 for (InstrumentTemplate* it : qAsConst(g->instrumentTemplates)) {
818 if (it->trackName == trackName)
819 return InstrumentIndex(grpIndex, instIndex, it);
820 ++instIndex;
821 }
822 ++grpIndex;
823 }
824 return InstrumentIndex(-1, -1, nullptr);
825 }
826
827 //---------------------------------------------------------
828 // searchTemplateIndexForId
829 //---------------------------------------------------------
830
searchTemplateIndexForId(const QString & id)831 InstrumentIndex searchTemplateIndexForId(const QString& id)
832 {
833 int instIndex = 0;
834 int grpIndex = 0;
835 for (InstrumentGroup* g : instrumentGroups) {
836 for (InstrumentTemplate* it : g->instrumentTemplates) {
837 if (it->id == id)
838 return InstrumentIndex(grpIndex, instIndex, it);
839 ++instIndex;
840 }
841 ++grpIndex;
842 }
843 return InstrumentIndex(-1, -1, nullptr);
844 }
845
846 //---------------------------------------------------------
847 // linkGenre
848 // link the current instrument template to the genre list specified by "genre"
849 // Each genre is a list of pointers to instrument templates
850 // The list of genres is at application level
851 //---------------------------------------------------------
852
linkGenre(const QString & genre)853 void InstrumentTemplate::linkGenre(const QString& genre)
854 {
855 InstrumentGenre *ig = searchInstrumentGenre(genre);
856 if (ig)
857 genres.append(ig);
858 }
859
860 //---------------------------------------------------------
861 // genreMember
862 // is this instrument template a member of the supplied genre
863 //---------------------------------------------------------
864
genreMember(const QString & name)865 bool InstrumentTemplate::genreMember(const QString& name)
866 {
867 bool rVal=false;
868 foreach(InstrumentGenre *instrumentGenre, genres ) {
869 if(instrumentGenre->id == name) {
870 rVal = true;
871 break;
872 }
873 }
874 return rVal;
875 }
876
write(XmlWriter & xml) const877 void InstrumentGenre::write(XmlWriter& xml) const
878 {
879 xml.stag(QString("Genre id=\"%1\"").arg(id));
880 xml.tag("name", name);
881 xml.etag();
882 }
883
write1(XmlWriter & xml) const884 void InstrumentGenre::write1(XmlWriter& xml) const
885 {
886 write(xml);
887 }
888
read(XmlReader & e)889 void InstrumentGenre::read(XmlReader& e)
890 {
891 id = e.attribute("id");
892 while (e.readNextStartElement()) {
893 const QStringRef& tag(e.name());
894 if (tag == "name") {
895 name = qApp->translate("InstrumentsXML", e.readElementText().toUtf8().data());
896 }
897 else
898 e.unknown();
899 }
900 }
901
902 //---------------------------------------------------------
903 // familyMember
904 // is this instrument template a member of the supplied family
905 //---------------------------------------------------------
906
familyMember(const QString & name)907 bool InstrumentTemplate::familyMember(const QString& name)
908 {
909 return family->id == name;
910 }
911
write(XmlWriter & xml) const912 void InstrumentFamily::write(XmlWriter& xml) const
913 {
914 xml.stag(QString("Family id=\"%1\"").arg(id));
915 xml.tag("name", name);
916 xml.etag();
917 }
918
write1(XmlWriter & xml) const919 void InstrumentFamily::write1(XmlWriter& xml) const
920 {
921 write(xml);
922 }
923
read(XmlReader & e)924 void InstrumentFamily::read(XmlReader& e)
925 {
926 id = e.attribute("id");
927 while (e.readNextStartElement()) {
928 const QStringRef& tag(e.name());
929 if (tag == "name") {
930 name = qApp->translate("InstrumentsXML", e.readElementText().toUtf8().data());
931 }
932 else
933 e.unknown();
934 }
935 }
936
937 //---------------------------------------------------------
938 // clefType
939 //---------------------------------------------------------
940
clefType(int staffIdx) const941 ClefTypeList InstrumentTemplate::clefType(int staffIdx) const
942 {
943 if (staffIdx < staves)
944 return clefTypes[staffIdx];
945 return clefTypes[0];
946 }
947
948 //---------------------------------------------------------
949 // defaultClef
950 // traverse the instrument list for first instrument
951 // with midi patch 'program'. Return the default clef
952 // for this instrument.
953 //---------------------------------------------------------
954
defaultClef(int program)955 ClefType defaultClef(int program)
956 {
957 if (program >= 24 && program < 32) // this are guitars
958 return ClefType::G8_VB;
959 else if (program >= 32 && program < 40) // this is bass
960 return ClefType::F8_VB;
961
962 for (InstrumentGroup* g : qAsConst(instrumentGroups)) {
963 for (InstrumentTemplate* it : qAsConst(g->instrumentTemplates)) {
964 if (it->channel[0].bank() == 0 && it->channel[0].program() == program){
965 return (it->clefTypes[0]._concertClef);
966 }
967 }
968 }
969 return ClefType::G;
970 }
971
972 }
973