1 //=============================================================================
2 //  MuseScore
3 //  Music Composition & Notation
4 //
5 //  Copyright (C) 2014 John Pirie
6 //  Parts of the GPX Import based on code contributed by J.Jørgen von Bargen
7 //
8 //  This program is free software; you can redistribute it and/or modify
9 //  it under the terms of the GNU General Public License version 2
10 //  as published by the Free Software Foundation and appearing in
11 //  the file LICENCE.GPL
12 //=============================================================================
13 
14 #include "importgtp.h"
15 
16 #include <libmscore/score.h>
17 #include <libmscore/measurebase.h>
18 #include <libmscore/text.h>
19 #include <libmscore/stafftext.h>
20 #include <libmscore/box.h>
21 #include <libmscore/staff.h>
22 #include <libmscore/part.h>
23 #include <libmscore/measure.h>
24 #include <libmscore/timesig.h>
25 #include <libmscore/tremolo.h>
26 #include <libmscore/rest.h>
27 #include <libmscore/chord.h>
28 #include <libmscore/note.h>
29 #include <libmscore/stringdata.h>
30 #include <libmscore/clef.h>
31 #include <libmscore/lyrics.h>
32 #include <libmscore/tempotext.h>
33 #include <libmscore/slur.h>
34 #include <libmscore/tie.h>
35 #include <libmscore/tuplet.h>
36 #include <libmscore/barline.h>
37 #include <libmscore/excerpt.h>
38 #include <libmscore/stafftype.h>
39 #include <libmscore/bracket.h>
40 #include <libmscore/articulation.h>
41 #include <libmscore/keysig.h>
42 #include <libmscore/harmony.h>
43 #include <libmscore/bend.h>
44 #include <libmscore/tremolobar.h>
45 #include <libmscore/segment.h>
46 #include <libmscore/rehearsalmark.h>
47 #include <libmscore/repeat.h>
48 #include <libmscore/glissando.h>
49 #include <libmscore/dynamic.h>
50 #include <libmscore/arpeggio.h>
51 #include <libmscore/volta.h>
52 #include <libmscore/instrtemplate.h>
53 #include <libmscore/hairpin.h>
54 #include <libmscore/fingering.h>
55 #include <libmscore/sym.h>
56 #include <libmscore/ottava.h>
57 #include <libmscore/marker.h>
58 #include <libmscore/notedot.h>
59 #include "libmscore/sym.h"
60 #include "libmscore/bracketItem.h"
61 #include "libmscore/textline.h"
62 #include <libmscore/repeat.h>
63 // #include <symtext.h>
64 
65 namespace Ms {
66 
67 
68 const std::map<QString, QString> GuitarPro6::instrumentMapping = {
69             {"2Mrcs",           "maracas"},
70             {"a-bass4",         "acoustic-bass"},
71             {"a-bass5",         "acoustic-bass"},
72             {"a-bass6",         "acoustic-bass"},
73             {"alt-c",           "alto"},
74             {"alt-s",           "alto"},
75             {"a-piano-gs",      "piano"},
76             {"a-piano-ss",      "piano"},
77             {"bass-c",          "bass"},
78             {"bass-flt-c",      "bass-flute"},
79             {"bassn",           "bassoon"},
80             {"bass-s",          "bass"},
81             {"basstuba-eb",     "bass-eb-tuba"},
82             {"bnj4",            "banjo"},
83             {"bnj5",            "banjo"},
84             {"bnj6",            "banjo"},
85             {"bongo",           "bongos"},
86             {"brthns",          "baritone-horn"},
87             {"brtn-c",          "baritone"},
88             {"brtn-s",          "baritone"},
89             {"cbs",             "cabasa"},
90             {"cello",           "violoncello"},
91             {"china",           "chinese-tom-toms"},
92             {"clrnt-a",         "a-clarinet"},
93             {"clrnt-bb-bass",   "bass-clarinet"},
94             {"clrnt-bb",        "bb-clarinet"},
95             {"clrnt-c",         "c-clarinet"},
96             {"clrnt-d",         "d-clarinet"},
97             {"clrnt-eb",        "eb-clarinet"},
98             {"clrnt",           "clarinet"},
99             {"clst-gs",         "celesta"},
100             {"clst-ss",         "celesta"},
101             {"clvs",            "claves"},
102             {"cngKit",          "congas"},
103             {"conga",           "congas"},
104             {"cowbell",         "cowbell"},
105             {"crash",           "crash-cymbal"},
106             {"cstnt",           "castanets"},
107             {"ctbassn",         "contrabassoon"},
108             {"ctbass",          "contrabass"},
109             {"cuicaKit",        "cuica"},
110             {"cuica",           "cuica"},
111             {"drmkt",           "drumset"},
112             {"e-bass4",         "bass-guitar"},
113             {"e-bass5",         "bass-guitar"},
114             {"e-bass6",         "bass-guitar"},
115             {"e-gtr12",         "electric-guitar-treble-clef"},
116             {"e-gtr6",          "electric-guitar-treble-clef"},
117             {"e-gtr7",          "electric-guitar-treble-clef"},
118             {"e-gtr8",          "electric-guitar-treble-clef"},
119             {"em-organ-gs",     "organ"},
120             {"em-organ-ss",     "organ"},
121             {"en-horn",         "english-horn"},
122             {"e-piano-gs",      "electric-piano"},
123             {"e-piano-ss",      "electric-piano"},
124             {"flt-c",           "flute"},
125             {"flt-g",           "alto-flute"},
126             {"flt-whstl",       "tin-whistle"},
127             {"fr-horn",         "horn"},
128             {"grcss",           "bass-drum"},   //grancassa is an alterantive name for bass drum
129             {"guiro",           "guiro"},
130             {"harp-gs",         "harp"},
131             {"harp-ss",         "harp"},
132             {"hclap",           "hand-clap"},
133             {"hihat",           "hi-hat"},
134             {"hrpch-gs",        "harpsichord"},
135             {"hrpch-ss",        "harpsichord"},
136             {"jngl-bell",       "sleigh-bells"},
137             {"klmb",            "kalimba"},
138             {"mrcs",            "maracas"},
139             {"n-gtr6",          "guitar-nylon-treble-clef"},
140             {"n-gtr7",          "guitar-nylon-treble-clef"},
141             {"n-gtr8",          "guitar-nylon-treble-clef"},
142             {"oboe",            "oboe"},
143             {"ocrn",            "ocarina"},
144             {"pccl",            "piccolo"},
145             {"pedalhihat",      "hi-hat"},
146             {"pnflt",           "pan-flute"},
147             {"ptt",             "cymbal"},  //piatti is cymbal in italian
148             {"rec",             "recorder"},
149             {"ride",            "ride-cymbal"},
150             {"rvs-cymb",        "cymbal"},
151             {"sax-alt-eb",      "alto-saxophone"},
152             {"sax-bar-eb",      "baritone-saxophone"},
153             {"sax-bass-eb",     "bass-saxophone"},
154             {"sax-ms-f",        "mezzo-soprano-saxophone"},
155             {"sax-sop-bb",      "soprano-saxophone"},
156             {"sax-ten-bb",      "tenor-saxophone"},
157             {"sax-ten-c",       "melody-saxophone"},
158             {"s-bass4",         "electric-bass"},
159             {"s-bass5",         "5-string-electric-bass"},
160             {"s-gtr12",         "guitar-steel-treble-clef"},
161             {"s-gtr6",          "guitar-steel-treble-clef"},
162             {"s-gtr7",          "guitar-steel-treble-clef"},
163             {"s-gtr8",          "guitar-steel-treble-clef"},
164             {"shkr",            "percussion"},
165             {"shmsn",           "shamisen"},
166             {"shn",             "sheng"},
167             {"snare",           "snare-drum"},
168             {"snr",             "snare-drum"},
169             {"snt-brass-gs",    "brass-synthesizer"},
170             {"snt-brass-ss",    "brass-synthesizer"},
171             //{"snt-key-gs",    ""},
172             //{"snt-key-ss",    ""},
173             //{"snt-seq-gs",    ""},
174             //{"snt-seq-ss",    ""},
175             {"snt-lead-gs",     "poly-synth"},
176             {"snt-lead-ss",     "poly-synth"},
177             {"snt-pad",         "pad-synth"},
178             {"snt-pad-gs",      "pad-synth"},
179             {"snt-pad-ss",      "pad-synth"},
180             {"splash",          "splash-cymbal"},
181             {"sprn-c",          "soprano"},
182             {"sprn-s",          "soprano"},
183             {"tmbrn",           "tambourine"}, // to be mapped
184             {"Tambourine-Perc", "tambourine"},
185             {"Tambourine",      "tambourine"},
186             {"tmblKit",         "timbales"},
187             {"tmbl",            "timbales"},
188             {"tmpn",            "timpani"},
189             {"tnklbll",         "tubular-bells"}, //The short form does not match but this is very likely due to the description
190             {"tnr-c",           "tenor"},
191             {"tnr-s",           "tenor"},
192             {"Triangle-Percu",  "triangle"},
193             {"trmbn-bb-bass",   "bass-trombone"},
194             {"trmbn-bb",        "tenor-trombone"},
195             {"trmbn-bb-treble", "trombone-treble"},
196             {"trmbn-eb",        "alto-trombone"},
197             {"trmpt-a",         "a-trumpet"},
198             {"trmpt-bb",        "bb-trumpet"},
199             {"trmpt-c-bass",    "c-bass-trumpet"},
200             {"trmpt-c",         "c-trumpet"},
201             {"trmpt-d",         "d-trumpet"},
202             {"trmpt-eb-bass",   "eb-bass-trumpet"},
203             {"trmpt-eb",        "eb-trumpet"},
204             {"trmpt-e",         "e-trumpet"},
205             {"trmpt-f",         "f-trumpet"},
206             {"trmpt-flgh",      "flugelhorn"},
207             {"trngl",           "triangle"},
208             {"ukll4",           "ukulele"},
209             {"vbrphn",          "vibraphone"},
210             {"vbrslp",          "vibraslap"}, // to be mapped
211             {"vla",             "viola"},
212             {"vln",             "violin"},
213             {"wdblckKit",       "wood-blocks"},
214             {"wdblck",          "wood-blocks"},
215             {"whstlKit",        "slide-whistle"},
216             {"whstl",           "tin-whistle"},
217             {"xlphn",           "xylophone"}
218             };
219 
220 //---------------------------------------------------------
221 //   readBit
222 //---------------------------------------------------------
223 
readBit(QByteArray * buffer)224 int GuitarPro6::readBit(QByteArray* buffer)
225       {
226       // calculate the byte index by dividing the position in bits by the bits per byte
227       int byteIndex = position / BITS_IN_BYTE;
228 
229       // calculate our offset so we know how much to bit shift
230       int byteOffset = ((BITS_IN_BYTE - 1) - (position % BITS_IN_BYTE));
231 
232       // calculate the bit which we want to read
233       int bit = ((((*buffer)[byteIndex] & 0xff) >> byteOffset) & 0x01);
234 
235       // increment our current position so we know this bit has been read
236       position++;
237       return bit;       // return the bit we calculated
238       }
239 
240 //---------------------------------------------------------
241 //   readBits
242 //---------------------------------------------------------
243 
readBits(QByteArray * buffer,int bitsToRead)244 int GuitarPro6::readBits(QByteArray* buffer, int bitsToRead)
245       {
246       int bits = 0;
247       for (int i = (bitsToRead - 1); i >= 0; i--)
248             bits |= (readBit(buffer) << i);
249       return bits;
250       }
251 
252 //---------------------------------------------------------
253 //   readBitsReversed
254 //---------------------------------------------------------
255 
readBitsReversed(QByteArray * buffer,int bitsToRead)256 int GuitarPro6::readBitsReversed(QByteArray* buffer, int bitsToRead)
257       {
258       int bits = 0;
259       for( int i = 0; i < bitsToRead; i++)
260             bits |= readBit(buffer) << i;
261       return bits;
262       }
263 
264 //---------------------------------------------------------
265 //   getBytes
266 //---------------------------------------------------------
267 
getBytes(QByteArray * buffer,int offset,int length)268 QByteArray GuitarPro6::getBytes(QByteArray* buffer, int offset, int length)
269       {
270       QByteArray newBytes;
271       // compute new bytes from our buffer and return byte array
272       for (int i = 0; i < length; i++) {
273             if (buffer->length() > offset + i)
274                   newBytes.insert(i, ((*buffer)[offset + i]));
275             }
276       return newBytes;
277       }
278 
279 //---------------------------------------------------------
280 //   readInteger
281 //---------------------------------------------------------
282 
readInteger(QByteArray * buffer,int offset)283 int GuitarPro6::readInteger(QByteArray* buffer, int offset)
284       {
285       // assign four bytes and take them from the buffer
286       char bytes[4];
287       bytes[0] = (*buffer)[offset + 0];
288       bytes[1] = (*buffer)[offset + 1];
289       bytes[2] = (*buffer)[offset + 2];
290       bytes[3] = (*buffer)[offset + 3];
291       // increment positioning so we keep track of where we are
292       position += sizeof(int) * BITS_IN_BYTE;
293       // bit shift in order to compute our integer value and return
294       return ((bytes[3] & 0xff) << 24) | ((bytes[2] & 0xff) << 16) | ((bytes[1] & 0xff) << 8) | (bytes[0] & 0xff);
295       }
296 
297 //---------------------------------------------------------
298 //   readString
299 //---------------------------------------------------------
300 
readString(QByteArray * buffer,int offset,int length)301 QByteArray GuitarPro6::readString(QByteArray* buffer, int offset, int length)
302       {
303       QByteArray filename;
304       // compute the string by iterating through the buffer
305       for (int i = 0; i < length; i++) {
306             int charValue = (((*buffer)[offset + i]) & 0xff);
307             if (charValue == 0)
308                   break;
309             filename.push_back((char)charValue);
310             }
311       return filename;
312       }
313 
314 
315 //---------------------------------------------------------
316 //   unhandledNode
317 //---------------------------------------------------------
318 
unhandledNode(QString nodeName)319 void GuitarPro6::unhandledNode(QString nodeName)
320       {
321       qDebug() << "WARNING: Discovered unhandled node name" << nodeName;
322       }
323 
324 //---------------------------------------------------------
325 //   readScore
326 //---------------------------------------------------------
327 
readScore(QDomNode * scoreNode)328 void GuitarPro6::readScore(QDomNode* scoreNode)
329       {
330       // loop through the score meta-info, grabbing title, artist, etc
331       QDomNode currentNode = scoreNode->firstChild();
332       while (!currentNode.isNull()) {
333             QString nodeName = currentNode.nodeName();
334             if (!nodeName.compare("Title"))
335                   title = currentNode.toElement().text();
336             if (!nodeName.compare("Copyright"))
337                   score->setMetaTag("copyright", currentNode.toElement().text());
338             else if (!nodeName.compare("SubTitle"))
339                   subtitle = currentNode.toElement().text();
340             else if (!nodeName.compare("Artist"))
341                   artist = currentNode.toElement().text();
342             else if (!nodeName.compare("Album"))
343                   album = currentNode.toElement().text();
344             else if (nodeName == "FirstPageHeader") {}
345             else if (nodeName == "FirstPageFooter") {}
346             else if (nodeName == "PageHeader") {}
347             else if (nodeName == "PageFooter") {}
348             else if (nodeName == "ScoreSystemsDefaultLayout") {}
349             else if (nodeName == "ScoreSystemsLayout") {}
350             currentNode = currentNode.nextSibling();
351             }
352       }
353 
354 //---------------------------------------------------------
355 //   readMasterTracks
356 //---------------------------------------------------------
357 
readMasterTracks(QDomNode * masterTrack)358 void GuitarPro6::readMasterTracks(QDomNode* masterTrack)
359       {
360       // inspects MasterTrack, gives information applying to start of score such as tempo
361       QDomNode currentNode = masterTrack->firstChild();
362       while (!currentNode.isNull()) {
363             QString nodeName = currentNode.nodeName();
364             if (!nodeName.compare("Automations")) {
365                   QDomNode currentAutomation = currentNode.firstChild();
366                   bool linearTemp { false };
367                   while (!currentAutomation.isNull()) {
368                         if (!currentAutomation.nodeName().compare("Automation")) {
369                               auto ln = currentAutomation.firstChildElement("Linear");
370                               if (!ln.isNull())
371                                     linearTemp = ln.text() == "true";
372                               auto first_name = currentAutomation.firstChild().nodeName();
373                               if (first_name == "Type")
374                                     first_name = currentAutomation.firstChild().toElement().text();
375                               if (!first_name.compare("Tempo")) {
376                                     QString t = currentAutomation.lastChild().toElement().text();
377                                     QStringList sa = t.split(" ");
378                                     int curtempo = 120;
379                                     if (sa.length() >= 1)
380                                           curtempo = sa[0].toInt();
381                                     auto barnode = currentAutomation.firstChildElement("Bar");
382                                     if (!barnode.isNull()) {
383                                           tempoMap[barnode.text().toInt()] = std::make_pair(curtempo, linearTemp);
384                                           }
385                                     }
386                               }
387                         currentAutomation = currentAutomation.nextSibling();
388                         }
389                   }
390             currentNode = currentNode.nextSibling();
391             }
392       }
393 
394 //---------------------------------------------------------
395 //   readChord
396 //---------------------------------------------------------
397 
readChord(QDomNode * diagram,int track)398 void GuitarPro6::readChord(QDomNode* diagram, int track)
399       {
400       // initialize a new fret diagram for our current track
401       FretDiagram* fretDiagram = new FretDiagram(score);
402       fretDiagram->setTrack(track);
403 
404       // get the identifier to set as the domain in the map
405       int id    = diagram->attributes().namedItem("id").toAttr().value().toInt();
406 //TODO-ws      auto name = diagram->attributes().namedItem("name").toAttr().value();
407 
408 //TODO-ws      fretDiagram->setChordName(name);
409       QDomNode diagramNode = diagram->firstChild();
410 
411       // set the number of strings on this part
412       int stringCount = diagramNode.attributes().namedItem("stringCount").toAttr().value().toInt();
413       fretDiagram->setStrings(stringCount);
414 
415       // set the fret offset
416       int baseFret = diagramNode.attributes().namedItem("baseFret").toAttr().value().toInt();
417       fretDiagram->setFretOffset(baseFret);
418 
419       QDomNode diagramEntity = diagramNode.firstChild();
420       int counter            = 0;
421       while (!diagramEntity.isNull()) {
422             QString nodeName = diagramEntity.nodeName();
423             // new fret
424             if (!nodeName.compare("Fret")) {
425                   // get the string and fret numbers from the arguments to the node as integers
426                   int string = diagramEntity.attributes().namedItem("string").toAttr().value().toInt();
427                   int fret   = diagramEntity.attributes().namedItem("fret").toAttr().value().toInt();
428 
429                   // if there are unspecified string values, add the X marker to that string
430                   while (counter < string) {
431                         fretDiagram->setMarker(counter, FretMarkerType::CROSS);
432                         counter++;
433                         }
434 
435                   // look at the specified string/fret and add to diagram
436                   if (fret == 0) {
437                         fretDiagram->setMarker(string, FretMarkerType::CIRCLE);
438                         counter++;
439                         }
440                   else {
441                         fretDiagram->setDot(string, fret, true);
442                         counter++;
443                         }
444                   }
445             // move to the next string/fret specification
446             diagramEntity = diagramEntity.nextSibling();
447             }
448 
449       // mark any missing strings as 'X'
450       while (counter < stringCount) {
451             fretDiagram->setMarker(counter, FretMarkerType::CROSS);
452             counter++;
453             }
454 
455       // insert the fret diagram into the map of diagrams
456       fretDiagrams.insert(id, fretDiagram);
457       }
458 
459 //---------------------------------------------------------
460 //   readTracks
461 //---------------------------------------------------------
462 
readTracks(QDomNode * track)463 void GuitarPro6::readTracks(QDomNode* track)
464       {
465       QDomNode nextTrack = track->firstChild();
466       int trackCounter   = 0;
467       while (!nextTrack.isNull()) {
468             QDomNode currentNode = nextTrack.firstChild();
469             Part* part           = new Part(score);
470             bool hasTuning       = false;
471             Staff* s             = new Staff(score);
472             s->setPart(part);
473             part->insertStaff(s, -1);
474             score->staves().push_back(s);
475             while (!currentNode.isNull()) {
476                   QString nodeName = currentNode.nodeName();
477                   if (nodeName == "Name")
478                         part->setPartName(currentNode.toElement().text());
479                   else if (nodeName == "Color") {}
480                   // this is a typo is guitar pro - 'defaut' is correct here
481                   else if (nodeName == "SystemsDefautLayout") {}
482                   else if (nodeName == "SystemsLayout") {}
483                   else if (nodeName == "RSE") {}
484                   else if (nodeName == "GeneralMidi") {
485                         if (currentNode.toElement().hasChildNodes()) {
486                               auto prog = currentNode.firstChildElement("Program");
487                               if (!prog.isNull()) {
488                                     auto p = prog.text().toInt();
489                                     part->instrument(Fraction(0,1))->channel(0)->setProgram(p);
490                                     }
491                               int midiChannel = currentNode.firstChildElement("PrimaryChannel").text().toInt();
492                               //if (!prog.isNull() && midiChannel != GP_DEFAULT_PERCUSSION_CHANNEL)
493                               // midiChannel += prog.text().toInt();
494                               part->setMidiChannel(midiChannel);
495                               if (midiChannel == GP_DEFAULT_PERCUSSION_CHANNEL) {
496                                     part->instrument()->setDrumset(gpDrumset);
497                                     s->setStaffType(Fraction(0,1), *StaffType::preset(StaffTypes::PERC_DEFAULT));
498                                     }
499                               }
500                         }
501                   else if (nodeName == "PlaybackState") {}
502                   else if (nodeName == "PlayingStyle") {}
503                   else if (nodeName == "PageSetup") {}
504                   else if (nodeName == "MultiVoice") {}
505                   else if (nodeName == "ShortName") {}
506                   else if (nodeName == "Instrument") {
507                         QString ref = currentNode.attributes().namedItem("ref").toAttr().value();
508                         auto it     = instrumentMapping.find(ref);
509                         if (it != instrumentMapping.end()) {
510                               part->setInstrument(Instrument::fromTemplate(Ms::searchTemplate(it->second)));
511                               }
512                         else
513                               qDebug() << "Unknown instrument: " << ref;
514                         if (ref.endsWith("-gs") || ref.startsWith("2")) { // grand staff
515                               Staff* s2 = new Staff(score);
516                               s2->setPart(part);
517                               part->insertStaff(s2, -1);
518                               score->staves().push_back(s2);
519                               s->addBracket(new BracketItem(s->score(), BracketType::BRACE, 2));
520                               s->setBarLineSpan(2);
521                               }
522                         }
523                   else if (nodeName == "PartSounding")
524                         part->instrument()->setTranspose(Interval(currentNode.firstChildElement("TranspositionPitch").text().toInt()));
525                   else if (nodeName == "Properties")
526                         readTrackProperties(currentNode, part, trackCounter, hasTuning);
527                   currentNode = currentNode.nextSibling();
528                   }
529 
530             // add in a new part
531             score->appendPart(part);
532             trackCounter++;
533             nextTrack = nextTrack.nextSibling();
534 
535             if (!hasTuning) {
536                   tunings.push_back("");
537                   }
538             }
539 
540       previousDynamic = new int[score->staves().length() * VOICES];
541       // initialise the dynamics to 0
542       for (int i = 0; i < score->staves().length() * VOICES; i++)
543             previousDynamic[i] = 0;
544       // set the number of staves we need
545       staves = score->staves().length();
546       }
547 
548 //---------------------------------------------------------
549 //   readTrackProperties
550 //---------------------------------------------------------
551 
readTrackProperties(const QDomNode & currentNode,Part * part,int trackCounter,bool & hasTuning)552 void GuitarPro6::readTrackProperties(const QDomNode& currentNode, Part* part, int trackCounter, bool& hasTuning)
553       {
554       QDomNode currentProperty = currentNode.firstChild();
555       while (!currentProperty.isNull()) {
556             QString propertyName = currentProperty.attributes().namedItem("name").toAttr().value();
557             if (!propertyName.compare("Tuning")) {
558                   // set up the tuning for the part
559                   QString tuningString = currentProperty.firstChild().toElement().text();
560                   QStringList tuningStringList = tuningString.split(" ");
561                   int strings = 0;
562                   std::vector<int> tuning(tuningStringList.length());
563                   //int tuning[tuningStringList.length()];
564                   int frets = 24;
565                   for (auto iter = tuningStringList.begin(); iter != tuningStringList.end(); ++iter) {
566                         int currentString = (*iter).toInt();
567                         tuning[strings] = currentString;
568                         strings++;
569                         }
570                   StringData* stringData = new StringData(frets, strings, &tuning[0]);
571                   Instrument* instr = part->instrument();
572                   instr->setStringData(*stringData);
573                   instr->setSingleNoteDynamics(false);
574                   hasTuning = true;
575                   createTuningString(strings, &tuning[0]);
576                   }
577             else if (!propertyName.compare("DiagramCollection")) {
578                   QDomNode items = currentProperty.firstChild();
579                   QDomNode currentItem = items.firstChild();
580                   while (!currentItem.isNull()) {
581                         readChord(&currentItem, trackCounter);
582                         currentItem = currentItem.nextSibling();
583                         }
584                   }
585             currentProperty = currentProperty.nextSibling();
586             }
587       }
588 
589 //---------------------------------------------------------
590 //   getNode
591 //---------------------------------------------------------
592 
getNode(const QString & id,QDomNode currentDomNode)593 QDomNode GuitarPro6::getNode(const QString& id, QDomNode currentDomNode)
594       {
595       while (!(currentDomNode).isNull()) {
596             QString currentId = currentDomNode.attributes().namedItem("id").toAttr().value();
597             if (id.compare(currentId) == 0) {
598                   return currentDomNode;
599                   }
600             currentDomNode = currentDomNode.nextSibling();
601             }
602       qDebug() << "WARNING: A null node was returned when search for the identifier" << id << ". Your Guitar Pro file may be corrupted.";
603       return currentDomNode;
604       }
605 
606 //---------------------------------------------------------
607 //   findNumMeasures
608 //---------------------------------------------------------
609 
findNumMeasures(GPPartInfo * partInfo)610 int GuitarPro6::findNumMeasures(GPPartInfo* partInfo)
611       {
612       QDomNode masterBar = partInfo->masterBars.nextSibling();
613       QDomNode masterBarElement;
614       while (!masterBar.isNull()) {
615             GpBar gpBar;
616             gpBar.freeTime       = false;
617             gpBar.direction      = "";
618             gpBar.directionStyle = "";
619             masterBarElement     = masterBar.firstChild();
620             while (!masterBarElement.isNull()) {
621                   if (!masterBarElement.nodeName().compare("Key"))
622                         gpBar.keysig = masterBarElement.firstChild().toElement().text().toInt();
623                   else if (!masterBarElement.nodeName().compare("Time")) {
624                         QString timeSignature            = masterBarElement.toElement().text();
625                         QList<QString> timeSignatureList = timeSignature.split("/");
626                         gpBar.timesig = Fraction(timeSignatureList.first().toInt(), timeSignatureList.last().toInt());
627                         }
628                   else if (!masterBarElement.nodeName().compare("Directions")) {
629                         auto element = masterBarElement.firstChild();
630                         while (!element.isNull()) {
631                               gpBar.directions.push_back(element.toElement().text());
632                               element = element.nextSibling();
633                               }
634                         //gpBar.direction = masterBarElement.firstChild().toElement().text();
635                         gpBar.directionStyle = masterBarElement.firstChild().nodeName();
636                         }
637                   else if (!masterBarElement.nodeName().compare("FreeTime")) {
638                         gpBar.freeTime = true;
639                         gpBar.barLine  = BarLineType::BROKEN;
640                         }
641                   else if (!masterBarElement.nodeName().compare("DoubleBar"))
642                         gpBar.barLine = BarLineType::DOUBLE;
643                   else if (!masterBarElement.nodeName().compare("Section")) {
644                         auto section = masterBarElement.firstChild();
645                         while (!section.isNull())
646                               {
647                               if (!section.nodeName().compare("Letter"))
648                                     gpBar.section[0] = section.toElement().text();
649                               else if (!section.nodeName().compare("Text"))
650                                     gpBar.section[1] = section.toElement().text();
651                               section = section.nextSibling();
652                               }
653                         }
654                   masterBarElement = masterBarElement.nextSibling();
655                   }
656             bars.append(gpBar);
657             if (masterBar.nextSibling().isNull())
658                   break;
659             masterBar = masterBar.nextSibling();
660             }
661       QString b = masterBar.lastChildElement("Bars").toElement().text();
662       //work out the number of measures (add 1 as couning from 0, and divide by number of parts)
663       int numMeasures = (b.split(" ").last().toInt() + 1) / score->parts().length();
664 
665       if (numMeasures > b.size()) {
666             qDebug("GuitarPro6:findNumMeasures: bars %d < numMeasures %d\n", b.size(), numMeasures);
667             // HACK (ws)
668             numMeasures = b.size();
669             }
670       return numMeasures;
671       }
672 
673 //---------------------------------------------------------
674 //   fermataToFraction
675 //---------------------------------------------------------
676 
fermataToFraction(int numerator,int denominator)677 Fraction GuitarPro6::fermataToFraction(int numerator, int denominator)
678       {
679       numerator++;
680       // minim through to hemidemisemiquaver
681       if (denominator == 0)       { denominator = 2; }
682       else if (denominator == 1) {
683             denominator = 4;
684             }
685       else if (denominator == 2) {
686             denominator = 8;
687             }
688       else if (denominator == 3) {
689             denominator = 12;
690             }
691       else if (denominator == 4) {
692             denominator = 16;
693             }
694       else if (denominator == 5) {
695             denominator = 32;
696             }
697 
698       return Fraction(numerator, denominator);
699       }
700 
701 //---------------------------------------------------------
702 //   rhythmToDuration
703 //---------------------------------------------------------
704 
rhythmToDuration(QString value)705 Fraction GuitarPro6::rhythmToDuration(QString value)
706       {
707       Fraction l;
708       if (value.compare("Whole") == 0)
709             l.set(1, 1);
710       else if (value.compare("Half") == 0)
711             l.set(1, 2);
712       else if (value.compare("Quarter") == 0)
713             l.set(1, 4);
714       else if (value.compare("Eighth") == 0)
715             l.set(1,8);
716       else if (value.compare("16th") == 0)
717             l.set(1,16);
718       else if (value.compare("32nd") == 0)
719             l.set(1,32);
720       else if (value.compare("64th") == 0)
721             l.set(1,64);
722       else if (value.compare("128th") == 0)
723             l.set(1,128);
724       else
725             qFatal( "Error - unknown note length: %s", qPrintable(value));
726       return l;
727       }
728 
729 //---------------------------------------------------------
730 //   readDrumNote
731 //---------------------------------------------------------
732 
readDrumNote(Note * note,int element,int variation)733 void GuitarPro6::readDrumNote(Note* note, int element, int variation)
734       {
735       int pitch = 44;
736       /* These numbers below were determined by creating all drum
737        * notes in a GPX format file and then analyzing the score.gpif
738        * file which specifies the score and then matching as much
739        * as possible with the gpDrumset...   */
740       if (element == 11 && variation == 0)  // pedal hihat
741             pitch = 44;
742       else if (element == 0 && variation == 0) // Kick (hit)
743             pitch = 36; // or 36
744       else if (element == 5 && variation == 0) // Tom very low (hit)
745             pitch = 41;
746       else if (element == 6 && variation == 0) // Tom low (hit)
747             pitch = 43;
748       else if (element == 7 && variation == 0) // Tom medium (hit)
749             pitch = 45;
750       else if (element == 1 && variation == 0) // Snare (hit)
751             pitch = 40; //or 40
752       else if (element == 1 && variation == 1) // Snare (rim shot)
753             pitch = 91;
754       else if (element == 1 && variation == 2) // Snare (side stick)
755             pitch = 37;
756       else if (element == 8 && variation == 0) // Tom high (hit)
757             pitch = 48;
758       else if (element == 9 && variation == 0) // Tom very high (hit)
759             pitch = 50;
760       else if (element == 15 && variation == 0) // Ride (middle)
761             pitch = 51;
762       else if (element == 15 && variation == 1) // Ride (edge)
763             pitch = 59;
764       else if (element == 15 && variation == 2) // Ride (bell)
765             pitch = 59;
766       else if (element == 10 && variation == 0) // Hihat (closed)
767             pitch = 42;
768       else if (element == 10 && variation == 1) // Hihat (half)
769             pitch = 46;
770       else if (element == 10 && variation == 2) // Hihat (open)
771             pitch = 46;
772       else if (element == 12 && variation == 0) // Crash medium (hit)
773             pitch = 49;
774       else if (element == 14 && variation == 0) // Splash (hit)
775             pitch = 55;
776       else if (element == 13 && variation == 0) // Crash high (hit)
777             pitch = 57;
778       else if (element == 16 && variation == 0) // China (hit)
779             pitch = 52;
780       else if (element == 4 && variation == 0) // Cowbell high (hit)
781             pitch = 102;
782       else if (element == 3 && variation == 0) // Cowbell medium (hit)
783             pitch = 56;
784       else if (element == 2 && variation == 0) // Cowbell low (hit)
785             pitch = 99;
786 
787       note->setPitch(pitch);
788       }
789 
790 
791 //---------------------------------------------------------
792 //   makeTie
793 //---------------------------------------------------------
794 
makeTie(Note * note)795 void GuitarPro6::makeTie(Note* note)
796       {
797       bool found       = false;
798       Chord* chord     = note->chord();
799       Segment* segment = chord->segment();
800       if (!segment)
801             return;
802       segment = segment->prev1(SegmentType::ChordRest);
803       int track = note->track();
804       while (segment) {
805             Element* e = segment->element(track);
806             if (e) {
807                   if (e->type() == ElementType::CHORD) {
808                         Chord* chord2 = static_cast<Chord*>(e);
809                         foreach(Note* note2, chord2->notes()) {
810                               if (note2->string() == note->string()) {
811                                     Tie* tie = new Tie(score);
812                                     tie->setEndNote(note);
813                                     note2->add(tie);
814                                     note->setFret(note2->fret());
815                                     note->setPitch(note2->pitch());
816                                     found = true;
817                                     break;
818                                     }
819                               }
820                         }
821                   if (found)
822                         break;
823                   }
824             segment = segment->prev1(SegmentType::ChordRest);
825             }
826       }
827 
828 //---------------------------------------------------------
829 //   readBeats
830 //---------------------------------------------------------
831 
readBeats(QString beats,GPPartInfo * partInfo,Measure * measure,const Fraction & startTick,int staffIdx,int voiceNum,Tuplet * tuplets[],int measureCounter)832 Fraction GuitarPro6::readBeats(QString beats, GPPartInfo* partInfo, Measure* measure, const Fraction& startTick, int staffIdx, int voiceNum, Tuplet* tuplets[], int measureCounter)
833       {
834       bool wrong_pause = false;
835       Lyrics* lyric    = nullptr;
836       Fraction beatsTick    = {0,1};
837 
838       // we must count from the start of the bar, so declare a fraction to track this
839       Fraction fermataIndex(0,1);
840       int track            = staffIdx * VOICES + voiceNum;
841       auto currentBeatList = beats.split(" ");
842       bool startSlur = false;
843       bool endSlur = false;
844       for (auto currentBeat = currentBeatList.begin(); currentBeat != currentBeatList.end(); currentBeat++) {
845             int sl = -1;
846             if (slides.contains(staffIdx * VOICES + voiceNum))
847                   sl = slides.take(staffIdx * VOICES + voiceNum);
848 
849             Fraction l;
850             int dotted           = 0;
851             QDomNode beat        = getNode(*currentBeat, partInfo->beats);
852             Fraction currentTick = startTick + beatsTick;
853             Segment* segment     = measure->getSegment(SegmentType::ChordRest, currentTick);
854             QDomNode currentNode = beat.firstChild();
855             bool noteSpecified   = false;
856             ChordRest* cr        = segment->cr(track);
857             bool tupletSet       = false;
858             Tuplet* tuplet       = tuplets[staffIdx * VOICES + voiceNum];
859             int whammyOrigin     = -1;
860             int whammyMiddle     = -1;
861             int whammyEnd        = -1;
862             bool graceNote       = false;
863             Note* lyrNote(nullptr);
864             std::map<int, QString> lyrics;
865             while (!currentNode.isNull()) {
866                   if (currentNode.nodeName() == "GraceNotes") {
867                         graceNote = true;
868                         }
869                   else if (currentNode.nodeName() == "Notes") {
870                         noteSpecified = true;
871                         auto notesList = currentNode.toElement().text().split(" ");
872 
873                         // this could be set by rhythm if we dealt with a tuplet
874                         if (!cr)
875                               cr = new Chord(score);
876                         if (lyric) {
877                               cr->add(lyric);
878                               lyric = nullptr;
879                               }
880                         cr->setTrack(track);
881                         cr->setTicks(l);
882                         TDuration d(l);
883                         d.setDots(dotted);
884 
885                         cr->setDurationType(d);
886 
887                         if (cr->isChord()) {
888                               auto lyrchord = toChord(cr);
889                               if (lyrchord && lyrchord->notes().size())
890                                     lyrNote = lyrchord->notes().front();
891                               }
892 
893                         if (!segment->cr(track))
894                               segment->add(cr);
895 
896                         if (startSlur) {
897                                     Slur* slur = new Slur(score);
898                                     slur->setParent(0);
899                                     slur->setTrack(track);
900                                     slur->setTrack2(track);
901                                     legatos[track] = slur;
902                                     slur->setTick(cr->tick());
903                                     slur->setTick2(cr->tick());
904                                     startSlur = false;
905                                     }
906                         if (endSlur) {
907                               Slur* slur = legatos[track];
908                               if (slur) {
909                                     slur->setTrack2(track);
910                                     slur->setTick2(cr->tick());
911                                     score->addElement(slur);
912                                     legatos[track] = 0;
913                                     }
914                               endSlur = false;
915                               }
916 
917                         Chord* lastChord { nullptr };
918                         for (auto iter = notesList.begin(); iter != notesList.end(); ++iter) {
919                               // we have found a note
920                               QDomNode dnote = getNode(*iter, partInfo->notes);
921                               int id        = -1;
922                               auto idx      = dnote.attributes().namedItem("id");
923                               if (!idx.isNull())
924                                     id = idx.nodeValue().toInt() - 1;
925                               QDomNode currentNote = (dnote).firstChild();
926                               bool tie             = false;
927                               bool trill           = false;
928                               // if a <Notes> tag is used but there is no <Note>, then we add a rest. This flag will allow us to check this.
929                               while (!currentNote.isNull()) {
930                                     if (!currentNote.nodeName().compare("Tie")) {
931                                           if (!currentNote.attributes().namedItem("destination").toAttr().value().compare("true"))
932                                                 tie = true;
933                                           }
934 
935                                     if (currentNote.nodeName() == "Properties") {
936                                           QDomNode currentProperty = currentNote.firstChild();
937                                           // these should not be in this scope - they may not even exist.
938                                           QString stringNum;
939                                           QString fretNum;
940                                           QString tone;
941                                           QString octave;
942                                           QString midi;
943                                           QString element;
944                                           QString variation;
945 
946                                           Note* note = new Note(score);
947                                           if (graceNote)
948                                                 lyrNote = note;
949                                           if (id != -1) {
950                                                 auto iter1 = lyrics.find(id);
951                                                 if (iter1 != lyrics.end()) {
952                                                       auto lyr = new Lyrics(score);
953                                                       lyr->setPlainText(iter1->second);
954                                                       cr->add(lyr);
955                                                       }
956                                                 }
957                                           lyrNote = note;
958                                           if (dotted) {
959                                                 // there is at most one dotted note in this guitar pro version
960                                                 NoteDot* dot = new NoteDot(score);
961                                                 dot->setParent(note);
962                                                 dot->setTrack(track);  // needed to know the staff it belongs to (and detect tablature)
963                                                 dot->setVisible(true);
964                                                 note->add(dot);
965                                                 }
966 
967                                           Chord* chord = static_cast<Chord*>(cr);
968                                           chord->add(note);
969                                           QString harmonicText = "";
970                                           bool use_harmonic    = true;
971                                           bool hasSlur         = false;
972                                           bool check_slide_map = true;
973 
974                                           while (!currentProperty.isNull()) {
975                                                 QString argument = currentProperty.attributes().namedItem("name").toAttr().value();
976                                                 if (argument == "String") {
977                                                       stringNum = currentProperty.firstChild().toElement().text();
978                                                       if (check_slide_map) {
979                                                             int string = stringNum.toInt();
980                                                             if (slideMap.find({ string, staffIdx }) != slideMap.end()) {
981                                                                   Note* start  = slideMap[{ string, staffIdx }];
982                                                                   Glissando* s = new Glissando(score);
983                                                                   s->setGlissandoType(GlissandoType::STRAIGHT);
984                                                                   note->chord()->add(s);
985                                                                   s->setAnchor(Spanner::Anchor::NOTE);
986                                                                   s->setStartElement(start);
987                                                                   s->setTick(start->chord()->tick());
988                                                                   s->setTrack(staffIdx);
989                                                                   s->setParent(start);
990                                                                   s->setEndElement(note);
991                                                                   s->setTick2(note->chord()->tick());
992                                                                   s->setTrack2(staffIdx);
993                                                                   score->addElement(s);
994                                                                   slideMap.erase({ string, staffIdx });
995                                                                   if (slurs[staffIdx])
996                                                                         createSlur(false, track, note->chord());
997                                                                   }
998                                                             }
999                                                       }
1000                                                 else if (argument == "Element")
1001                                                       element = currentProperty.firstChild().toElement().text();
1002                                                 else if (argument == "Slide") {
1003                                                       int slideKind = currentProperty.firstChild().toElement().text().toInt();
1004                                                       if (slideKind & (SHIFT_SLIDE | LEGATO_SLIDE)) {
1005                                                             auto string = note->string();
1006                                                             if (string == -1) {
1007                                                                   for (auto node = currentNote.firstChild(); !node.isNull(); node = node.nextSibling()) {
1008                                                                         auto arg = node.attributes().namedItem("name").toAttr().value();
1009                                                                         if (arg == "String") {
1010                                                                               string = node.firstChild().toElement().text().toInt();
1011                                                                               break;
1012                                                                               }
1013                                                                         }
1014                                                                   }
1015                                                             if (slideKind & LEGATO_SLIDE)
1016                                                                   note->setFlag(ElementFlag::HAS_TAG, true);
1017                                                             slideMap.insert({ { string, staffIdx }, note });
1018                                                             slideKind      &= ~(SHIFT_SLIDE | LEGATO_SLIDE);
1019                                                             check_slide_map = false;
1020                                                             }
1021                                                       if (slideKind) {
1022                                                             createSlide(slideKind, note->chord(), staffIdx, note);
1023 #if 0
1024                                                             if (slideKind >= 4)
1025                                                                   slide = slideKind;
1026                                                             else
1027                                                                   slides->insert(staffIdx * VOICES + voiceNum, slideKind);
1028 #endif
1029                                                             }
1030                                                       }
1031                                                 else if (!argument.compare("HopoOrigin")) {
1032                                                       hasSlur = true;
1033                                                       createSlur(true, track, cr);
1034                                                       }
1035                                                 else if (!argument.compare("HopoDestination") && !hasSlur) {
1036                                                       createSlur(false, track, cr);
1037                                                       }
1038                                                 else if (argument == "Variation")
1039                                                       variation = currentProperty.firstChild().toElement().text();
1040                                                 else if (argument == "Fret")
1041                                                       fretNum = currentProperty.firstChild().toElement().text();
1042                                                 else if (argument == "Tone")
1043                                                       tone = currentProperty.firstChild().toElement().text();
1044                                                 else if (argument == "Octave")
1045                                                       octave = currentProperty.firstChild().toElement().text();
1046                                                 else if (argument == "Midi")
1047                                                       midi = currentProperty.firstChild().toElement().text();
1048                                                 else if (argument == "Muted") {
1049                                                       if (!currentProperty.firstChild().nodeName().compare("Enable")) {
1050                                                             note->setHeadGroup(NoteHead::Group::HEAD_CROSS);
1051                                                             note->setGhost(true);
1052                                                             }
1053                                                       }
1054                                                 else if (argument == "Tapped") {
1055                                                       if (!currentProperty.firstChild().nodeName().compare("Enable"))
1056                                                             addTap(note);
1057                                                       }
1058                                                 else if (argument == "LeftHandTapped") {
1059                                                       if (!currentProperty.firstChild().nodeName().compare("Enable")) {
1060                                                             Symbol* sym = new Symbol(note->score());
1061                                                             sym->setSym(SymId::articLaissezVibrerAbove);
1062                                                             sym->setParent(note);
1063                                                             note->add(sym);
1064                                                             //note->setStemThrough(true);
1065                                                             //articLaissezVibrerAbove
1066                                                             /*
1067                                                             Symbol* leftSym = new Symbol(note->score());
1068                                                             Symbol* rightSym = new Symbol(note->score());
1069                                                             leftSym->setSym(SymId::noteheadParenthesisLeft);
1070                                                             rightSym->setSym(SymId::noteheadParenthesisRight);
1071                                                             leftSym->setParent(note);
1072                                                             rightSym->setParent(note);
1073                                                             note->add(leftSym);
1074                                                             note->add(rightSym);
1075                                                             */
1076                                                             }
1077                                                       }
1078                                                 else if (argument == "Bended") {
1079                                                       if (!currentProperty.firstChild().nodeName().compare("Enable")) {
1080                                                             auto props = currentProperty.nextSibling();
1081                                                             int origin(0);
1082                                                             int destination(0);
1083                                                             int off1(15);
1084                                                             int off2(0);
1085                                                             int offdest(60);
1086                                                             int middleval(0);
1087                                                             bool has_middle = false;
1088                                                             while (!props.isNull()) {
1089                                                                   auto name = props.attributes().namedItem("name").toAttr().value();
1090                                                                   if (name == "BendOriginValue") {
1091                                                                         origin = props.firstChildElement("Float").toElement().text().toInt();
1092                                                                         }
1093                                                                   else if (name == "BendDestinationValue") {
1094                                                                         destination = props.firstChildElement("Float").toElement().text().toInt();
1095                                                                         }
1096                                                                   else if (name == "BendMiddleOffset1") {
1097                                                                         off1 = props.firstChildElement("Float").toElement().text().toInt();
1098                                                                         }
1099                                                                   else if (name == "BendMiddleOffset2") {
1100                                                                         off2 = props.firstChildElement("Float").toElement().text().toInt();
1101                                                                         }
1102                                                                   else if (name == "BendDestinationOffset") {
1103                                                                         offdest = props.firstChildElement("Float").toElement().text().toInt();
1104                                                                         }
1105                                                                   else if (name == "BendMiddleValue") {
1106                                                                         middleval  = props.firstChildElement("Float").toElement().text().toInt();
1107                                                                         has_middle = true;
1108                                                                         }
1109                                                                   props = props.nextSibling();
1110                                                                   }
1111 
1112                                                             Bend* bend = new Bend(note->score());
1113                                                             //bend->setNote(note); //TODO
1114                                                             bend->points().append(PitchValue(0, origin));
1115                                                             bend->points().append(PitchValue(off1, has_middle ? middleval : destination));
1116                                                             if (has_middle)
1117                                                                   bend->points().append(PitchValue(off2, middleval));
1118                                                             bend->points().append(PitchValue(offdest, destination));
1119                                                             note->add(bend);
1120                                                             }
1121                                                       }
1122                                                 else if (argument == "PalmMuted") {
1123                                                       if (!currentProperty.firstChild().nodeName().compare("Enable"))
1124                                                             addPalmMute(note);
1125                                                       }
1126                                                 else if (!argument.compare("HarmonicType")) {
1127                                                       QString type;
1128                                                       auto inner = currentProperty.firstChildElement("HType");
1129                                                       if (inner.isNull())
1130                                                             type = currentProperty.toElement().text();
1131                                                       else
1132                                                             type = inner.toElement().text();
1133                                                       // add the same text to the note that Guitar Pro does
1134                                                       if (!type.compare("Feedback"))
1135                                                             harmonicText = "Fdbk.";
1136                                                       else if (!type.compare("Semi"))
1137                                                             harmonicText = "S.H.";
1138                                                       else if (!type.compare("Pinch"))
1139                                                             harmonicText = "P.H.";
1140                                                       else if (!type.compare("Tap"))
1141                                                             harmonicText = "T.H.";
1142                                                       else if (!type.compare("Artificial"))
1143                                                             harmonicText = "A.H.";
1144                                                       else {
1145                                                             harmonicText = type;
1146                                                             use_harmonic = false;
1147                                                             }
1148                                                       }
1149                                                 else if (!argument.compare("HarmonicFret")) {
1150                                                       QString value;
1151                                                       auto inner = currentProperty.firstChildElement("HFret");
1152                                                       if (inner.isNull())
1153                                                             value = currentProperty.toElement().text();
1154                                                       else
1155                                                             value = inner.toElement().text();
1156                                                       Note* harmonicNote = nullptr;
1157 
1158                                                       // natural harmonic = artificial harmonic?
1159                                                       if (harmonicText.length()) {
1160                                                             if (!harmonicText.compare("Natural")) {
1161                                                                   harmonicNote = note;
1162                                                                   //note->setHarmonic(true); //TODO
1163                                                                   }
1164                                                             else {
1165                                                                   harmonicNote = new Note(score);
1166                                                                   // harmonicNote->setHarmonic(true);
1167                                                                   //harmonicNote->setTrillFret(11);
1168                                                                   chord->add(harmonicNote);
1169 
1170                                                                   //harmonicNote->setVisible(false);
1171                                                                   }
1172                                                             }
1173 
1174                                                       if (harmonicNote) {
1175                                                       #if 0
1176                                                             if (harmonicNote->harmonic())
1177                                                                   value = "";
1178                                                             if (harmonicText == "A.H.")
1179                                                                   harmonicNote->setHarmonic(true);
1180                                                       #endif
1181                                                             Staff* staff        = note->staff();
1182                                                             int harmonicFret    = fretNum.toInt();
1183                                                             int musescoreString = staff->part()->instrument()->stringData()->strings() - 1 - stringNum.toInt();
1184                                                             harmonicNote->setString(musescoreString);
1185                                                             harmonicNote->setFret(harmonicFret);                     // add the octave for the harmonic
1186                                                             harmonicNote->setHeadGroup(NoteHead::Group::HEAD_DIAMOND);
1187                                                             if (!value.compare("12"))
1188                                                                   harmonicFret += 12;
1189                                                             else if (!value.compare("7") || !value.compare("19"))
1190                                                                   harmonicFret += 19;
1191                                                             else if (!value.compare("5") || !value.compare("24"))
1192                                                                   harmonicFret += 24;
1193                                                             else if (!value.compare("3.9") || !value.compare("4") || !value.compare("9") || !value.compare("16"))
1194                                                                   harmonicFret += 28;
1195                                                             else if (!value.compare("3.2"))
1196                                                                   harmonicFret += 31;
1197                                                             else if (!value.compare("2.7"))
1198                                                                   harmonicFret += 34;
1199                                                             else if (!value.compare("2.3") || !value.compare("2.4"))
1200                                                                   harmonicFret += 36;
1201                                                             else if (!value.compare("2"))
1202                                                                   harmonicFret += 38;
1203                                                             else if (!value.compare("1.8"))
1204                                                                   harmonicFret += 40;
1205                                                             //harmonicNote->setFret(harmonicFret);
1206                                                             harmonicNote->setPitch(staff->part()->instrument()->stringData()->getPitch(musescoreString, harmonicFret, nullptr, Fraction(0,1)));
1207                                                             harmonicNote->setTpcFromPitch();
1208                                                             if (harmonicText.length() && harmonicText.compare("Natural")) {
1209                                                                   harmonicNote->setFret(fretNum.toInt());
1210                                                                   if (use_harmonic)
1211                                                                         harmonicText += "\\";
1212                                                                   addTextToNote(harmonicText, Align::CENTER, harmonicNote);
1213                                                                   }
1214                                                             }
1215                                                       }
1216                                                 currentProperty = currentProperty.nextSibling();
1217                                                 }
1218 
1219                                           if (midi != "")
1220                                                 note->setPitch(midi.toInt());
1221                                           else if (element != "")
1222                                                 readDrumNote(note, element.toInt(), variation.toInt());
1223                                           else if (stringNum != "" && stringNum.toInt() >= 0 && note->headGroup() != NoteHead::Group::HEAD_DIAMOND) {
1224                                                 Staff* staff        = note->staff();
1225                                                 int fretNumber      = fretNum.toInt();
1226                                                 int musescoreString = staff->part()->instrument()->stringData()->strings() - 1 - stringNum.toInt();
1227                                                 auto pitch          = staff->part()->instrument()->stringData()->getPitch(musescoreString, fretNumber, nullptr, Fraction(0,1));
1228                                                 note->setFret(fretNumber);
1229                                                 // we need to turn this string number for GP to the correct string number for musescore
1230                                                 note->setString(musescoreString);
1231                                                 note->setPitch(pitch);
1232                                                 }
1233                                           else if (tone != "")
1234                                                 note->setPitch((octave.toInt() * 12) + tone.toInt()); // multiply octaves by 12 as 12 semitones in octave
1235                                           if (tie) {
1236                                                 makeTie(note);
1237                                                 tie = false;
1238                                                 }
1239                                           if (trill) {
1240                                                 Articulation* art = new Articulation(note->score());
1241                                                 art->setSymId(SymId::ornamentTrill);
1242                                                 if (!note->score()->addArticulation(note, art))
1243                                                       delete art;
1244                                                 }
1245                                           QDomNode tremoloNode = currentNode.parentNode().firstChildElement("Tremolo");
1246                                           if (!tremoloNode.isNull()) {
1247                                                 QString value = tremoloNode.toElement().text();
1248                                                 Tremolo* t    = new Tremolo(chord->score());
1249                                                 if (!value.compare("1/2")) {
1250                                                       t->setTremoloType(TremoloType::R8);
1251                                                       chord->add(t);
1252                                                       }
1253                                                 else if (!value.compare("1/4")) {
1254                                                       t->setTremoloType(TremoloType::R16);
1255                                                       chord->add(t);
1256                                                       }
1257                                                 else if (!value.compare("1/8")) {
1258                                                       t->setTremoloType(TremoloType::R32);
1259                                                       chord->add(t);
1260                                                       }
1261                                                 }
1262                                           QDomNode wahNode = currentNode.parentNode().firstChildElement("Wah");
1263                                           if (!wahNode.isNull()) {
1264                                                 QString value = wahNode.toElement().text();
1265                                                 if (!value.compare("Open")) {
1266                                                       Articulation* art = new Articulation(note->score());
1267                                                       art->setSymId(SymId::brassMuteOpen);
1268                                                       if (!note->score()->addArticulation(note, art))
1269                                                             delete art;
1270                                                       }
1271                                                 else if (!value.compare("Closed")) {
1272                                                       Articulation* art = new Articulation(note->score());
1273                                                       art->setSymId(SymId::brassMuteClosed);
1274                                                       if (!note->score()->addArticulation(note, art))
1275                                                             delete art;
1276                                                       }
1277                                                 }
1278                                           QDomNode accentNode = currentNote.parentNode().firstChildElement("Accent");
1279                                           if (!accentNode.isNull()) {
1280                                                 int value   = accentNode.toElement().text().toInt();
1281                                                 SymId symId = SymId::articStaccatoAbove;
1282                                                 switch (value) {
1283                                                       case 1: symId  = SymId::articStaccatoAbove; break;
1284                                                       case 2: symId  = SymId::articStaccatissimoAbove; break;
1285                                                       case 4: symId  = SymId::articMarcatoAbove; break;
1286                                                       case 8: symId  = SymId::articAccentAbove; break;
1287                                                       case 16: symId = SymId::articTenutoAbove; break;
1288                                                       }
1289                                                 Articulation* art = new Articulation(note->score());
1290                                                 art->setSymId(symId);
1291                                                 if (!note->score()->addArticulation(note, art))
1292                                                       delete art;
1293                                                 }
1294                                           QDomNode ornamentNode = currentNote.parentNode().firstChildElement("Ornament");
1295                                           if (!ornamentNode.isNull()) {
1296                                                 QString value = ornamentNode.toElement().text();
1297                                                 // guitar pro represents the turns the other way to what we do
1298                                                 if (!value.compare("InvertedTurn")) {
1299                                                       Articulation* art = new Articulation(note->score());
1300                                                       art->setSymId(SymId::ornamentTurn);
1301                                                       if (!note->score()->addArticulation(note, art))
1302                                                             delete art;
1303                                                       }
1304                                                 else if (!value.compare("Turn")) {
1305                                                       Articulation* art = new Articulation(note->score());
1306                                                       art->setSymId(SymId::ornamentTurnInverted);
1307                                                       if (!note->score()->addArticulation(note, art))
1308                                                             delete art;
1309                                                       }
1310                                                 else if (!value.compare("LowerMordent")) {
1311                                                       Articulation* art = new Articulation(note->score());
1312                                                       art->setSymId(SymId::ornamentMordent);
1313                                                       if (!note->score()->addArticulation(note, art))
1314                                                             delete art;
1315                                                       }
1316                                                 else if (!value.compare("UpperMordent")) {
1317                                                       Articulation* art = new Articulation(note->score());
1318                                                       art->setSymId(SymId::ornamentShortTrill);
1319                                                       if (!note->score()->addArticulation(note, art))
1320                                                             delete art;
1321                                                       }
1322                                                 }
1323                                           QDomNode propertiesNode = currentNode.parentNode().firstChildElement("Properties");
1324                                           if (!propertiesNode.isNull()) {
1325                                                 QDomNode currentProperty1 = propertiesNode.firstChild();
1326                                                 QString barreFret        = "";
1327                                                 bool halfBarre           = false;
1328                                                 while (!currentProperty1.isNull()) {
1329                                                       QString argument = currentProperty1.attributes().namedItem("name").toAttr().value();
1330                                                       if (!argument.compare("PickStroke")) {
1331                                                             if (!currentProperty1.firstChild().toElement().text().compare("Up")) {
1332                                                                   Articulation* art = new Articulation(note->score());
1333                                                                   art->setSymId(SymId::stringsUpBow);
1334                                                                   if (!note->score()->addArticulation(note, art))
1335                                                                         delete art;
1336                                                                   }
1337                                                             else if (!currentProperty1.firstChild().toElement().text().compare("Down")) {
1338                                                                   Articulation* art = new Articulation(note->score());
1339                                                                   art->setSymId(SymId::stringsDownBow);
1340                                                                   if (!note->score()->addArticulation(note, art))
1341                                                                         delete art;
1342                                                                   }
1343                                                             }
1344                                                       else if (!argument.compare("Brush")) {
1345                                                             Arpeggio* a = new Arpeggio(score);
1346                                                             // directions in arpeggion type are reversed, they are correct below
1347                                                             if (!currentProperty1.firstChild().toElement().text().compare("Up"))
1348                                                                   a->setArpeggioType(ArpeggioType::DOWN_STRAIGHT);
1349                                                             else if (!currentProperty1.firstChild().toElement().text().compare("Down"))
1350                                                                   a->setArpeggioType(ArpeggioType::UP_STRAIGHT);
1351                                                             chord->add(a);
1352                                                             }
1353                                                       else if (!argument.compare("Slapped")) {
1354                                                             if (!currentProperty1.firstChild().nodeName().compare("Enable"))
1355                                                                   addSlap(note);
1356                                                             }
1357                                                       else if (!argument.compare("Popped")) {
1358                                                             if (!currentProperty1.firstChild().nodeName().compare("Enable"))
1359                                                                   addPop(note);
1360                                                             }
1361                                                       else if (!argument.compare("VibratoWTremBar")) {
1362                                                             if (!currentProperty1.firstChild().toElement().text().compare("Slight"))
1363                                                                   addVibrato(note, Vibrato::Type::VIBRATO_SAWTOOTH);
1364                                                             else
1365                                                                   addVibrato(note, Vibrato::Type::VIBRATO_SAWTOOTH_WIDE);
1366                                                             }
1367                                                       else if (!argument.compare("BarreFret")) {
1368                                                             // target can be anywhere from 1 to 36
1369                                                             int target = currentProperty1.firstChild().toElement().text().toInt();
1370                                                             for (int i = 0; i < (target / 10); i++)
1371                                                                   barreFret += "X";
1372                                                             int targetMod10 = target % 10;
1373                                                             if (targetMod10 == 9)
1374                                                                   barreFret += "IX";
1375                                                             else if (targetMod10 == 4)
1376                                                                   barreFret += "IV";
1377                                                             else {
1378                                                                   if (targetMod10 >= 5) {
1379                                                                         barreFret   += "V";
1380                                                                         targetMod10 -= 5;
1381                                                                         }
1382                                                                   for (int j = 0; j < targetMod10; j++)
1383                                                                         barreFret += "I";
1384                                                                   }
1385                                                             }
1386                                                       else if (!argument.compare("BarreString"))
1387                                                             halfBarre = true;
1388                                                       else if (!argument.compare("WhammyBarOriginValue"))
1389                                                             whammyOrigin = currentProperty1.firstChild().toElement().text().toInt();
1390                                                       else if (!argument.compare("WhammyBarMiddleValue"))
1391                                                             whammyMiddle = currentProperty1.firstChild().toElement().text().toInt();
1392                                                       else if (!argument.compare("WhammyBarDestinationValue"))
1393                                                             whammyEnd = currentProperty1.firstChild().toElement().text().toInt();
1394                                                       currentProperty1 = currentProperty1.nextSibling();
1395                                                       }
1396 
1397                                                 if (whammyOrigin != -1) {
1398                                                       // a whammy bar has been detected
1399                                                       addTremoloBar(segment, track, whammyOrigin, whammyMiddle, whammyEnd);
1400                                                       }
1401 
1402                                                 // if a barre fret has been specified
1403                                                 if (barreFret.compare("") && lastChord != note->chord()) {
1404                                                       lastChord = note->chord();
1405                                                       if (halfBarre)
1406                                                             addTextToNote("1/2B " + barreFret, Align::CENTER, note);
1407                                                       else
1408                                                             addTextToNote("B " + barreFret, Align::CENTER, note);
1409                                                       }
1410                                                 }
1411                                           QDomNode dynamicsNode = currentNode.parentNode().firstChildElement("Dynamic");
1412                                           if (!dynamicsNode.isNull()) {
1413                                                 QString dynamicStr = dynamicsNode.toElement().text();
1414                                                 int dynamic        = 0;
1415                                                 if (!dynamicStr.compare("PPP"))
1416                                                       dynamic = 1;
1417                                                 else if (!dynamicStr.compare("PP"))
1418                                                       dynamic = 2;
1419                                                 else if (!dynamicStr.compare("P"))
1420                                                       dynamic = 3;
1421                                                 else if (!dynamicStr.compare("MP"))
1422                                                       dynamic = 4;
1423                                                 else if (!dynamicStr.compare("MF"))
1424                                                       dynamic = 5;
1425                                                 else if (!dynamicStr.compare("F"))
1426                                                       dynamic = 6;
1427                                                 else if (!dynamicStr.compare("FF"))
1428                                                       dynamic = 7;
1429                                                 else if (!dynamicStr.compare("FFF"))
1430                                                       dynamic = 8;
1431                                                 if (previousDynamic[track] != dynamic) {
1432                                                       previousDynamic[track] = dynamic;
1433                                                       addDynamic(note, dynamic);
1434                                                       }
1435                                                 }
1436                                           /* while left and right fingering nodes have distinct values, they are represented
1437                                            * the same way w.r.t. identifying digit/char in the score file. */
1438                                           QDomNode leftFingeringNode  = currentNote.parentNode().firstChildElement("LeftFingering");
1439                                           QDomNode rightFingeringNode = currentNote.parentNode().firstChildElement("RightFingering");
1440                                           if (!leftFingeringNode.isNull() || !rightFingeringNode.isNull()) {
1441                                                 QDomNode fingeringNode = leftFingeringNode.isNull() ? rightFingeringNode : leftFingeringNode;
1442                                                 QString finger         = fingeringNode.toElement().text();
1443                                                 Fingering* fi          = new Fingering(score);
1444                                                 if (!leftFingeringNode.isNull()) {
1445                                                       if (!finger.compare("Open"))
1446                                                             finger = "O";
1447                                                       else if (!finger.compare("P"))
1448                                                             finger = "t";
1449                                                       else if (!finger.compare("I"))
1450                                                             finger = "1";
1451                                                       else if (!finger.compare("M"))
1452                                                             finger = "2";
1453                                                       else if (!finger.compare("A"))
1454                                                             finger = "3";
1455                                                       else if (!finger.compare("C"))
1456                                                             finger = "4";
1457                                                       }
1458                                                 fi->setPlainText(finger);
1459                                                 note->add(fi);
1460                                                 fi->reset();
1461                                                 }
1462                                           QDomNode arpeggioNode = currentNode.parentNode().firstChildElement("Arpeggio");
1463                                           if (!arpeggioNode.isNull()) {
1464                                                 QString arpeggioStr = arpeggioNode.toElement().text();
1465                                                 Arpeggio* a         = new Arpeggio(score);
1466                                                 if (!arpeggioStr.compare("Up"))
1467                                                       a->setArpeggioType(ArpeggioType::DOWN);
1468                                                 else
1469                                                       a->setArpeggioType(ArpeggioType::NORMAL);
1470                                                 chord->add(a);
1471                                                 }
1472                                           QDomNode letRingNode = currentNote.parentNode().firstChildElement("LetRing");
1473                                           if (!letRingNode.isNull())
1474                                                 addLetRing(note);
1475 #if 0
1476                                           QDomNode timerNode = currentNode.parentNode().firstChildElement("Timer");
1477                                           if (!timerNode.isNull()) {
1478                                                 int time = timerNode.toElement().text().toInt();
1479                                                 TextStyle textStyle;
1480                                                 textStyle.setAlign(Align::CENTER);
1481                                                 textStyle.setUnderline(true);
1482                                                 int minutes = time / 60;
1483                                                 int seconds = time % 60;
1484                                                 addTextToNote(QString::number(minutes) + ":" + (seconds < 10 ? "0" + QString::number(seconds) : QString::number(seconds)), textStyle, note);
1485                                                 }
1486 #endif
1487                                           QDomNode textNode = currentNode.parentNode().firstChildElement("FreeText");
1488                                           if (!textNode.isNull()) {
1489                                                 QString text      = textNode.toElement().text();
1490                                                 bool t            = false;
1491                                                 // do not add twice the same text per staff
1492                                                 int strack = staffIdx * VOICES;
1493                                                 int etrack = staffIdx * VOICES + VOICES;
1494                                                 for (const Element* e : segment->annotations()) {
1495                                                       if (e->type() == ElementType::STAFF_TEXT && e->track() >= strack && e->track() < etrack) {
1496                                                             const StaffText* st = static_cast<const StaffText*>(e);
1497                                                             if (!st->xmlText().compare(text)) {
1498                                                                   t = true;
1499                                                                   break;
1500                                                                   }
1501                                                             }
1502                                                       }
1503                                                 if (!t && !text.isEmpty()) {
1504                                                       StaffText* s = new StaffText(score);
1505                                                       s->setPlainText(text);
1506                                                       s->setTrack(track);
1507                                                       segment->add(s);
1508                                                       }
1509                                                 }
1510                                           QDomNode ghostNode = currentNote.parentNode().firstChildElement("AntiAccent");
1511                                           if (!ghostNode.isNull()) {
1512                                                 note->setGhost(true);
1513                                                 /*Symbol* leftSym = new Symbol(note->score());
1514                                                 Symbol* rightSym = new Symbol(note->score());
1515                                                 leftSym->setSym(SymId::noteheadParenthesisLeft);
1516                                                 rightSym->setSym(SymId::noteheadParenthesisRight);
1517                                                 leftSym->setParent(note);
1518                                                 rightSym->setParent(note);
1519                                                 note->add(leftSym);
1520                                                 note->add(rightSym);*/
1521                                                 }
1522                                           QDomNode swellNode = currentNode.parentNode().firstChildElement("Fadding");
1523                                           if (!swellNode.isNull()) {
1524                                                 auto str          = swellNode.toElement().text();
1525                                                 Articulation* art = new Articulation(note->score());
1526                                                 if (str == "FadeIn")
1527                                                       art->setSymId(SymId::guitarFadeIn);
1528                                                 else if (str == "FadeOut")
1529                                                       art->setSymId(SymId::guitarFadeOut);
1530                                                 else if (str == "VolumeSwell")
1531                                                       art->setSymId(SymId::guitarVolumeSwell);
1532                                                 art->setAnchor(ArticulationAnchor::TOP_STAFF);
1533                                                 art->setPropertyFlags(Pid::ARTICULATION_ANCHOR, PropertyFlags::UNSTYLED);
1534                                                 if (!note->score()->addArticulation(note, art))
1535                                                       delete art;
1536                                                 }
1537                                           QDomNode noteVibrato = currentNote.parentNode().firstChildElement("Vibrato");
1538                                           if (!noteVibrato.isNull()) {
1539                                                 if (!noteVibrato.toElement().text().compare("Slight"))
1540                                                       addVibrato(note, Vibrato::Type::GUITAR_VIBRATO);
1541                                                 else
1542                                                       addVibrato(note, Vibrato::Type::GUITAR_VIBRATO_WIDE);
1543                                                 }
1544 
1545                                           if (cr && (cr->type() == ElementType::CHORD) && sl > 0)
1546                                                 createSlide(sl, cr, staffIdx);
1547                                           note->setTpcFromPitch();
1548 
1549                                           /* if the ottava is a continuation (need to end old one), or we don't
1550                                           * see one in the current note when we are tracking one then end the ottava. */
1551                                           if (ottavaFound.at(track) == 2 || (ottavaFound.at(track) == 1 && currentNode.parentNode().firstChildElement("Ottavia").isNull())) {
1552                                                 createOttava(false, track, cr, ottavaValue.at(track));
1553                                                 if (ottavaFound.at(track) == 2)
1554                                                       ottavaFound.at(track) = 1;
1555                                                 else
1556                                                       ottavaFound.at(track) = 0;
1557                                                 }
1558                                           if (ottavaFound.at(track)) {
1559                                                 createOttava(true, track, cr, ottavaValue.at(track));
1560                                                 int pitch       = note->pitch();
1561                                                 OttavaType type = ottava.at(track)->ottavaType();
1562                                                 if (type == OttavaType::OTTAVA_8VA)
1563                                                       note->setPitch( (pitch - 12 > 0) ? pitch - 12 : pitch);
1564                                                 else if (type == OttavaType::OTTAVA_8VB)
1565                                                       note->setPitch( (pitch + 12 < 127) ? pitch + 12 : pitch);
1566                                                 else if (type == OttavaType::OTTAVA_15MA)
1567                                                       note->setPitch( (pitch - 24 > 0) ? pitch - 24 : (pitch - 12 > 0 ? pitch - 12 : pitch));
1568                                                 else if (type == OttavaType::OTTAVA_15MB)
1569                                                       note->setPitch( (pitch + 24 < 127) ? pitch + 24 : ( (pitch + 12 < 127) ? pitch + 12 :  pitch));
1570                                                 }
1571 
1572                                           currentNote = currentNote.nextSibling();
1573                                           }
1574                                     else if (!currentNote.nodeName().compare("Trill")) {
1575                                           trill = true;
1576                                           }
1577                                     currentNote = currentNote.nextSibling();
1578                                     }
1579 
1580                               if (graceNote) {
1581                                     QDomNode graceNode = currentNode.parentNode().firstChildElement("GraceNotes");
1582                                     if (!graceNode.isNull()) {
1583                                           lyrNote->setTpcFromPitch();
1584                                           auto chord = lyrNote->chord();
1585                                           // before beat grace notes have to be handled after the Tpc is set from pitch
1586                                           if (!graceNode.toElement().text().compare("OnBeat")) {
1587                                                 auto gNote = score->setGraceNote(chord, lyrNote->pitch(), NoteType::GRACE4, MScore::division / 2);
1588                                                 auto iter1  = slideMap.end();
1589                                                 for (auto beg = slideMap.begin(); beg != slideMap.end(); ++beg) {
1590                                                       if (beg->second == lyrNote) {
1591                                                             iter1 = beg;
1592                                                             break;
1593                                                             }
1594                                                       }
1595                                                 if (iter1 != slideMap.end()) {
1596                                                       iter1->second = gNote;
1597                                                       createSlur(true, staffIdx, gNote->chord());
1598                                                       }
1599                                                 if (lyrNote->chord()->notes().size() > 1) {
1600                                                       lyrNote->chord()->remove(lyrNote);
1601                                                       delete lyrNote;
1602                                                       lyrNote = nullptr;
1603                                                       }
1604                                                 }
1605                                           else if (!graceNode.toElement().text().compare("BeforeBeat") && chord->type() == ElementType::CHORD) {
1606                                                 auto gNote = score->setGraceNote(chord, lyrNote->pitch(), NoteType::ACCIACCATURA, MScore::division / 2);
1607                                                 auto iter1  = slideMap.end();
1608                                                 for (auto beg = slideMap.begin(); beg != slideMap.end(); ++beg) {
1609                                                       if (beg->second == lyrNote) {
1610                                                             iter1 = beg;
1611                                                             break;
1612                                                             }
1613                                                       }
1614                                                 if (iter1 != slideMap.end()) {
1615                                                       iter1->second = gNote;
1616                                                       //slideMap.erase(iter);
1617                                                       //slideMap.insert({ { lyrNote->string(), lyrNote->staffIdx() }, gNote });
1618                                                       }
1619                                                 //lyrNote->chord()->remove(lyrNote);
1620                                                 //delete lyrNote;
1621                                                 lyrNote = nullptr;
1622                                                 }
1623                                           }
1624                                     }
1625                               continue;
1626                               }
1627                         }
1628                   else if (currentNode.nodeName() == "Dynamic") {}
1629                   else if (!currentNode.nodeName().compare("Chord")) {
1630                         int k = currentNode.toElement().text().toInt();
1631                         if (fretDiagrams[k]) {
1632                               // TODO: free fretDiagrams
1633                               segment->add(new FretDiagram(*fretDiagrams[k]));
1634                               }
1635                         }
1636                   else if (currentNode.nodeName() == "Timer") {
1637                         //int time    = currentNode.toElement().text().toInt();
1638                         //int minutes = time / 60;
1639                         //int seconds = time % 60;
1640                         //addTextToNote(QString::number(minutes) + ":" + (seconds < 10 ? "0" + QString::number(seconds) : QString::number(seconds)), Align::CENTER, note); //TODO
1641                         }
1642                   else if (currentNode.nodeName() == "Rhythm") {
1643                         // we have found a rhythm
1644                         QString refString     = currentNode.attributes().namedItem("ref").toAttr().value();
1645                         QDomNode rhythm       = getNode(refString, partInfo->rhythms);
1646                         QDomNode currentNode1 = (rhythm).firstChild();
1647                         while (!currentNode1.isNull()) {
1648                               if (currentNode1.nodeName() == "NoteValue") {
1649                                     l = rhythmToDuration(currentNode1.toElement().text());
1650                                     }
1651                               else if (currentNode1.nodeName() == "AugmentationDot") {
1652                                     dotted = currentNode1.attributes().namedItem("count").toAttr().value().toInt();
1653                                     Fraction tmp = l;
1654                                     for (int count = 1; count <= dotted; count++)
1655                                           l = l + (tmp / Fraction(pow(2, count),1));
1656                                     }
1657                               else if (currentNode1.nodeName() == "PrimaryTuplet") {
1658                                     tupletSet = true;
1659                                     cr        = new Chord(score);
1660                                     cr->setParent(segment);
1661                                     cr->setTrack(track);
1662                                     if ((tuplet == 0) || (tuplet->elementsDuration() == tuplet->baseLen().fraction() * tuplet->ratio().numerator())) {
1663                                           tuplet                           = new Tuplet(score);
1664                                           tuplet->setTick(currentTick);
1665                                           tuplets[staffIdx * VOICES + voiceNum] = tuplet;
1666                                           tuplet->setParent(measure);
1667                                           }
1668                                     tuplet->setTrack(cr->track());
1669                                     tuplet->setBaseLen(l);
1670                                     tuplet->setRatio(Fraction(currentNode1.attributes().namedItem("num").toAttr().value().toInt(),currentNode1.attributes().namedItem("den").toAttr().value().toInt()));
1671                                     setupTupletStyle(tuplet);
1672                                     tuplet->setTicks(l * tuplet->ratio().denominator());
1673                                     tuplet->add(cr);
1674                                     }
1675                               else
1676                                     qDebug() << "WARNING: Not handling node: " << currentNode1.nodeName();
1677                               currentNode1 = currentNode1.nextSibling();
1678                               }
1679                         fermataIndex += l;
1680                         }
1681                   else if (currentNode.nodeName() == "Legato") {
1682                         QString origin = currentNode.attributes().namedItem("origin").toAttr().value();
1683                         QString destination = currentNode.attributes().namedItem("destination").toAttr().value();
1684                         if (!destination.compare("false") && !origin.compare("true")) {
1685                               qDebug() << "origin";
1686                               startSlur = true;
1687                               }
1688                         else if (!destination.compare("true") && !origin.compare("false")) {
1689                               qDebug() << "destination";
1690                               endSlur = true;
1691                               }
1692                         }
1693                   else if (currentNode.nodeName() == "Hairpin") {
1694                         Segment* seg = segment->prev1(SegmentType::ChordRest);
1695                         bool isCrec  = !currentNode.toElement().text().compare("Crescendo");
1696                         if (seg && hairpins[staffIdx]) {
1697                               if (hairpins[staffIdx]->tick2() == seg->tick() &&
1698                                  ((isCrec && hairpins[staffIdx]->hairpinType() == HairpinType::CRESC_HAIRPIN) ||
1699                                  (!isCrec && hairpins[staffIdx]->hairpinType() == HairpinType::DECRESC_HAIRPIN)))
1700                                     hairpins[staffIdx]->setTick2(currentTick);
1701                               else
1702                                     createCrecDim(staffIdx, track, currentTick, isCrec);
1703                               }
1704                         else
1705                               createCrecDim(staffIdx, track, currentTick, isCrec);
1706                         }
1707                   else if (!currentNode.nodeName().compare("Properties")) {
1708                         QDomNode currentProperty = currentNode.firstChild();
1709                         while (!currentProperty.isNull()) {
1710                               QString argument = currentProperty.attributes().namedItem("name").toAttr().value();
1711                               if (!argument.compare("Rasgueado")) {
1712                                     ChordRest* cr1 = segment->cr(track);
1713                                     if (cr1 && cr1->isChord()) {
1714                                           Chord* c = toChord(cr1);
1715                                           addTextToNote("rasg.", Align::LEFT, c->upNote());
1716                                           }
1717 #if 0
1718                                     StaffText* st = new StaffText(score);
1719                                     st->setTextStyleType(TextStyleType::STAFF);
1720                                     st->setXmlText("rasg.");
1721                                     st->setParent(segment);
1722                                     st->setTrack(track);
1723                                     score->addElement(st);
1724 #endif
1725                                     }
1726                               currentProperty = currentProperty.nextSibling();
1727                               }
1728                         }
1729                   else if (!currentNode.nodeName().compare("Ottavia")) {
1730                         /* if we saw an ottava and have an updated
1731                         * information string, set to 2 indicating that. */
1732                         if (ottavaFound.at(track) == 1 && ottavaValue.at(track).compare(currentNode.toElement().text()))
1733                               ottavaFound.at(track) = 2;
1734                         else
1735                               ottavaFound.at(track) = 1;
1736                         ottavaValue.at(track) = currentNode.toElement().text();
1737                         }
1738                   else if (currentNode.nodeName() == "Lyrics") {
1739                         auto lyrNode = currentNode.firstChildElement("Line");
1740                         auto str     = lyrNode.toElement().text();
1741                         //if (lyrNote) lyrNote->setLyric(str);
1742                         auto lyr = new Lyrics(score);
1743                         lyr->setPlainText(str);
1744                         if (cr)
1745                               cr->add(lyr);
1746                         else
1747                               lyric = lyr;
1748                         }
1749                   else if (currentNode.nodeName() == "FreeText") {
1750                         //TODO::
1751 #if 0
1752                         auto str = currentNode.toElement().text();
1753                         auto lyr = new Lyrics(score);
1754                         lyr->setPlainText(str);
1755                         cr->add(lyr);
1756                         if (lyrNote)
1757                               lyrNote->setLyric(str);
1758                         else {
1759                               auto nt = beat.firstChildElement("Notes");
1760                               if (!nt.isNull()) {
1761                                     auto notelist = nt.toElement().text().split(' ');
1762                                     lyrics[notelist.first().toInt()] = str;
1763                                     }
1764                               }
1765 #endif
1766                         }
1767                   currentNode = currentNode.nextSibling();
1768                   }
1769             dotted = 0;
1770             if (graceNote)
1771                   continue;
1772             // we have handled the beat - was there a note?
1773             if (!noteSpecified) {
1774                   // add a rest with length of l
1775                   // we already have a chord, delete it first
1776                   ChordRest* prevCr = cr; // added in "Rhythm"
1777                   cr = new Rest(score);
1778                   if (track % VOICES != 0)
1779                         wrong_pause = true;
1780                   cr->setTrack(track);
1781                   if (tupletSet) {
1782                         tuplet->remove(prevCr);
1783                         delete prevCr;
1784                         tuplet->add(cr);
1785                         }
1786                   cr->setTicks(l);
1787                   if (cr->type() == ElementType::REST && l >= measure->ticks()) {
1788                         cr->setDurationType(TDuration::DurationType::V_MEASURE);
1789                         cr->setTicks(measure->ticks());
1790                         }
1791                   else {
1792                         TDuration d(l);
1793                         cr->setDurationType(d);
1794                         }
1795                   if (!segment->cr(track))
1796                         segment->add(cr);
1797                   }
1798             auto fermataList = fermatas.find(measureCounter);
1799             if (fermataList != fermatas.end()) {
1800                   // iterator is a list of GPFermata values
1801                   //for (auto fermataIter = (*fermataList)->begin(); fermataIter != (*fermataList)->end(); fermataIter++) {
1802 
1803                   auto fermataIter     = (*fermataList)->begin();
1804                   Fraction targetIndex = fermataToFraction((*fermataIter).index, ((*fermataIter).timeDivision));
1805                   if (fermataIndex == targetIndex) {
1806                         Articulation* art = new Articulation(score);
1807                         art->setSymId(SymId::fermataAbove);
1808                         if (fermataIter->type == "Long")
1809                               art->setSymId(SymId::fermataLongAbove);
1810                         art->setUp(true);
1811                         art->setAnchor(ArticulationAnchor::TOP_STAFF);
1812                         art->setPropertyFlags(Pid::ARTICULATION_ANCHOR, PropertyFlags::UNSTYLED);
1813                         auto seg = cr->segment()->prev1(SegmentType::ChordRest);
1814                         if (seg && seg->cr(track)->isChord()) {
1815                               seg->cr(track)->add(art);
1816                               }
1817                         else
1818                               cr->add(art);
1819                         }
1820                   //}
1821                   }
1822             beatsTick += cr->actualTicks();
1823             }
1824 
1825       if (wrong_pause) {
1826             _lastTick = beatsTick;
1827             return Fraction(-1,1);
1828             }
1829       return beatsTick;
1830       }
1831 
1832 //---------------------------------------------------------
1833 //   readBars
1834 //---------------------------------------------------------
1835 
readBars(QDomNode * barList,Measure * measure,ClefType oldClefId[],GPPartInfo * partInfo,int measureCounter)1836 void GuitarPro6::readBars(QDomNode* barList, Measure* measure, ClefType oldClefId[], GPPartInfo* partInfo, int measureCounter)
1837       {
1838       // unique bar identifiers are represented as a space separated string of numbers
1839       QStringList barsString = barList->toElement().text().split(" ");
1840       int staffIdx           = 0;
1841 
1842       // used to keep track of tuplets
1843       std::vector<Tuplet*> tuplets(staves * VOICES);
1844       for (int track = 0; track < staves * VOICES; ++track)
1845             tuplets[track] = 0;
1846 
1847       // iterate through all the bars that have been specified
1848       for (auto iter = barsString.begin(); iter != barsString.end(); ++iter) {
1849             Fraction tick = measure->tick();
1850 
1851             QDomNode barNode     = getNode(*iter, partInfo->bars);
1852             QDomNode currentNode = (barNode).firstChild();
1853             QDomNode voice;
1854             while (!currentNode.isNull()) {
1855                   voice.clear();
1856                   // get the clef of the bar and apply
1857                   if (!currentNode.nodeName().compare("Clef")) {
1858                         QString clefString = currentNode.toElement().text();
1859                         QDomNode nextNode  = currentNode.nextSibling();
1860                         QString clefOctave;
1861                         if (!nextNode.nodeName().compare("Ottavia"))
1862                               clefOctave = nextNode.toElement().text();
1863                         ClefType clefId = ClefType::G;
1864                         if (!clefString.compare("F4")) {
1865                               clefId = ClefType::F;
1866                               if (clefOctave == "8va")
1867                                     clefId = ClefType::F_8VA;
1868                               else if (clefOctave == "8vb")
1869                                     clefId = ClefType::F8_VB;
1870                               else if (clefOctave == "15ma")
1871                                     clefId = ClefType::F_15MA;
1872                               else if (clefOctave == "15mb")
1873                                     clefId = ClefType::F15_MB;
1874                               }
1875                         else if (!clefString.compare("G2")) {
1876                               clefId = ClefType::G;
1877                               if (clefOctave == "8va")
1878                                     clefId = ClefType::G8_VA;
1879                               else if (clefOctave == "8vb")
1880                                     clefId = ClefType::G8_VB;
1881                               else if (clefOctave == "15ma")
1882                                     clefId = ClefType::G15_MA;
1883                               else if (clefOctave == "15mb")
1884                                     clefId = ClefType::G15_MB;
1885                               }
1886                         else if (!clefString.compare("C3"))
1887                               clefId = ClefType::C3;
1888                         else if (!clefString.compare("C4"))
1889                               clefId = ClefType::C4;
1890                         else if (!clefString.compare("Neutral"))
1891                               clefId = ClefType::PERC;
1892                         else
1893                               qDebug() << "WARNING: unhandled clef type: " << clefString;
1894                         Clef* newClef = new Clef(score);
1895                         newClef->setClefType(clefId);
1896                         newClef->setTrack(staffIdx * VOICES);
1897                         // only add the clef to the bar if it differs from previous measure
1898                         if (measure->prevMeasure()) {
1899                               if (clefId != oldClefId[staffIdx]) {
1900                                     Segment* segment = measure->getSegment(SegmentType::Clef, tick);
1901                                     segment->add(newClef);
1902                                     oldClefId[staffIdx] = clefId;
1903                                     }
1904                               else
1905                                     delete newClef;
1906                               }
1907                         else {
1908                               Segment* segment = measure->getSegment(SegmentType::HeaderClef, Fraction(0,1));
1909                               segment->add(newClef);
1910                               oldClefId[staffIdx] = clefId;
1911                               }
1912                         }
1913                   // a repeated bar (simile marking)
1914                   else if (!currentNode.nodeName().compare("SimileMark")) {
1915                         if (!currentNode.toElement().text().compare("Simple") ||
1916                            !currentNode.toElement().text().compare("FirstOfDouble") ||
1917                            !currentNode.toElement().text().compare("SecondOfDouble")) {
1918                               RepeatMeasure* rm = new RepeatMeasure(score);
1919                               rm->setTrack(staffIdx * VOICES);
1920                               rm->setTicks(measure->ticks());
1921                               rm->setDurationType(TDuration::DurationType::V_MEASURE);
1922                               Segment* segment = measure->getSegment(SegmentType::ChordRest, tick);
1923                               segment->add(rm);
1924                               }
1925                         else
1926                               qDebug() << "WARNING: unhandle similie mark type: " << currentNode.toElement().text();
1927                         }
1928                   // new voice specification
1929                   else if (!currentNode.nodeName().compare("Voices")) {
1930                         QString voicesString = currentNode.toElement().text();
1931                         auto voices          = voicesString.split(" ");
1932                         bool contentAdded    = false;
1933                         int voiceNum         = -1;
1934                         for (const auto &currentVoice : qAsConst(voices)) {
1935                               // if the voice is not -1 then we set voice
1936                               if (currentVoice.compare("-1"))
1937                                     voice = getNode(currentVoice, partInfo->voices);
1938                               voiceNum += 1;
1939                               if (currentVoice.toInt() == -1) {
1940                                     if (contentAdded) continue;
1941                                     Fraction l = measure->ticks();
1942                                     // add a rest with length of l
1943                                     ChordRest* cr = new Rest(score);
1944                                     cr->setTrack(staffIdx * VOICES + voiceNum);
1945                                     cr->setTicks(l);
1946                                     cr->setDurationType(TDuration::DurationType::V_MEASURE);
1947                                     Segment* segment = measure->getSegment(SegmentType::ChordRest, tick);
1948                                     if(!segment->cr(staffIdx * VOICES + voiceNum))
1949                                           segment->add(cr);
1950                                     contentAdded = true;
1951                                     continue;
1952                                     }
1953                               // read the beats that occur in the bar
1954                               Fraction ticks = readBeats(voice.firstChild().toElement().text(), partInfo, measure, tick, staffIdx, voiceNum, &tuplets[0], measureCounter);
1955                               if (ticks > Fraction(0,1))
1956                                     contentAdded = true;
1957                               // deal with possible anacrusis
1958                               if (ticks < measure->ticks() && voiceNum == 0) {
1959                                     Fraction mticks = measure->ticks();
1960                                     Fraction tickOffSet = mticks - ticks;
1961                                     int track            = staffIdx * VOICES + voiceNum;
1962                                     score->setRest(ticks + measure->tick(), track, tickOffSet, true, nullptr, true);
1963                                     }
1964                               }
1965                         }
1966                   else if (!currentNode.nodeName().compare("XProperties")) {}
1967                   // go to the next node in the tree
1968                   currentNode = currentNode.nextSibling();
1969                   }
1970             // increment the counter for parts
1971             staffIdx++;
1972             }
1973       }
1974 
1975 //---------------------------------------------------------
1976 //   checkForHeld
1977 //---------------------------------------------------------
1978 
checkForHold(Segment * segment,QList<PitchValue> points)1979 bool checkForHold(Segment* segment, QList<PitchValue> points)
1980       {
1981       bool same        = false;
1982       Segment* prevSeg = segment->prev1(SegmentType::ChordRest);
1983       if (!prevSeg)
1984             return false;
1985       foreach (Element* e, prevSeg->annotations()) {
1986             if (e->type() == ElementType::TREMOLOBAR) {
1987                   QList<PitchValue> prevPoints = ((TremoloBar*)e)->points();
1988                   if (prevPoints.length() != points.length())
1989                         break;
1990 
1991                   auto iter = points.begin();
1992                   for (auto prevIter = prevPoints.begin(); prevIter != prevPoints.end(); ++prevIter) {
1993                         if (*prevIter == *iter)
1994                               same = true;
1995                         else {
1996                               same = false;
1997                               break;
1998                               }
1999                         ++iter;
2000                         }
2001                   }
2002             }
2003       return same;
2004       }
2005 
2006 //---------------------------------------------------------
2007 //   addTremoloBar
2008 //---------------------------------------------------------
2009 
addTremoloBar(Segment * segment,int track,int whammyOrigin,int whammyMiddle,int whammyEnd)2010 void GuitarPro6::addTremoloBar(Segment* segment, int track, int whammyOrigin, int whammyMiddle, int whammyEnd)
2011       {
2012       if (whammyOrigin == 0 && whammyMiddle == 0 && whammyEnd == 0)
2013             return;
2014       if ((whammyOrigin == whammyEnd) && (whammyOrigin != whammyMiddle) && whammyMiddle != -1) {
2015             /* we are dealing with a dip. We need the check for whammy middle
2016              * to be set as a predive has the same characteristics. */
2017             QList<PitchValue> points;
2018             points.append(PitchValue(0, whammyOrigin, false));
2019             points.append(PitchValue(50, whammyMiddle, false));
2020             points.append(PitchValue(100, whammyEnd, false));
2021             TremoloBar* b = new TremoloBar(score);
2022             b->setPoints(points);
2023             b->setTrack(track);
2024             segment->add(b);
2025             }
2026       else if (whammyOrigin == 0) {
2027             // we're dealing with a dive that does not continue from a previous marking
2028             QList<PitchValue> points;
2029             points.append(PitchValue(0, whammyOrigin, false));
2030             points.append(PitchValue(50, whammyMiddle, false));
2031             points.append(PitchValue(100, whammyEnd, false));
2032             TremoloBar* b = new TremoloBar(score);
2033             b->setPoints(points);
2034             b->setTrack(track);
2035             segment->add(b);
2036             }
2037       else if (whammyOrigin == whammyEnd && whammyMiddle == -1) {
2038             // this deals with a pre-dive
2039             QList<PitchValue> points;
2040             points.append(PitchValue(0, 0, false));
2041             points.append(PitchValue(50, whammyOrigin, false));
2042             points.append(PitchValue(100, whammyEnd, false));
2043             TremoloBar* b = new TremoloBar(score);
2044             b->setPoints(points);
2045             b->setTrack(track);
2046             segment->add(b);
2047             }
2048       else if (whammyMiddle != -1) {
2049             // dive starting from pre-existing point
2050             Segment* prevSeg = segment->prev1(SegmentType::ChordRest);
2051             if (!prevSeg)
2052                   return;
2053             foreach (Element* e, prevSeg->annotations()) {
2054                   if (e->type() == ElementType::TREMOLOBAR) {
2055                         QList<PitchValue> prevPoints = ((TremoloBar*)e)->points();
2056                         QList<PitchValue> points;
2057                         points.append(PitchValue(0, prevPoints[prevPoints.length() - 1].pitch, false));
2058                         points.append(PitchValue(50, whammyOrigin, false));
2059                         points.append(PitchValue(100, whammyEnd, false));
2060                         TremoloBar* b = new TremoloBar(score);
2061                         b->setPoints(points);
2062                         b->setTrack(track);
2063                         segment->add(b);
2064                         }
2065                   }
2066             }
2067       else {
2068             // a predive/dive
2069             QList<PitchValue> points;
2070             points.append(PitchValue(0, 0, false));
2071             points.append(PitchValue(50, whammyOrigin, false));
2072             points.append(PitchValue(100, whammyEnd, false));
2073 
2074             if (checkForHold(segment, points)) {
2075                   points.clear();
2076                   points.append(PitchValue(0, whammyEnd, false));
2077                   points.append(PitchValue(100, whammyEnd, false));
2078                   }
2079 
2080             TremoloBar* b = new TremoloBar(score);
2081             b->setPoints(points);
2082             b->setTrack(track);
2083             segment->add(b);
2084             }
2085       }
2086 
2087 //---------------------------------------------------------
2088 //   readMasterBars
2089 //---------------------------------------------------------
2090 
readMasterBars(GPPartInfo * partInfo)2091 void GuitarPro6::readMasterBars(GPPartInfo* partInfo)
2092       {
2093       Measure* measure       = score->firstMeasure();
2094       int bar                = 0;
2095       QDomNode nextMasterBar = partInfo->masterBars;
2096       nextMasterBar = nextMasterBar.nextSibling();
2097       int measureCounter = 0;
2098       //int last_counter   = -1, last_counter2 = -1, max_counter = -1;
2099       std::vector<ClefType> oldClefId(staves);
2100       //ClefType oldClefId[staves];
2101       hairpins = new Hairpin*[staves];
2102       for (int i = 0; i < staves; i++)
2103             hairpins[i] = 0;
2104       do    {
2105             const GpBar& gpbar = bars[bar];
2106 
2107             if (!gpbar.marker.isEmpty()) {
2108                   RehearsalMark* s = new RehearsalMark(score);
2109                   s->setPlainText(gpbar.marker.trimmed());
2110                   s->setTrack(0);
2111                   Segment* segment = measure->getSegment(SegmentType::ChordRest, measure->tick());
2112                   segment->add(s);
2113                   }
2114 
2115             QDomNode masterBarElementTemplate = nextMasterBar.firstChild();
2116             for (int stave = 0; stave < staves; stave++) {
2117                   QDomNode masterBarElement = masterBarElementTemplate;
2118                   bool first                = true;
2119                   while (!masterBarElement.isNull()) {
2120                         if (first) {
2121                               if (bars[measureCounter].freeTime /*&& last_counter != measureCounter*/) {
2122                                     //last_counter = measureCounter;
2123                                     bool previousFreeTime = (measureCounter > 0 && bars[measureCounter - 1].freeTime);
2124                                     bool sameTimeSig = measureCounter > 0 && (bars[measureCounter - 1].timesig == bars[measureCounter].timesig);
2125                                     if (!sameTimeSig) {
2126                                           TimeSig* ts = new TimeSig(score);
2127                                           ts->setSig(bars[measureCounter].timesig);
2128                                           ts->setTrack(stave);
2129                                           Measure* m = score->getCreateMeasure(measure->tick());
2130                                           Segment* s = m->getSegment(SegmentType::TimeSig, measure->tick());
2131                                           ts->setLargeParentheses(true);
2132                                           s->add(ts);
2133                                           // no text for two consecutive freetime timesig
2134                                           if (!previousFreeTime) {
2135                                                 StaffText* st = new StaffText(score);
2136                                                 st->setXmlText("Free time");
2137                                                 s = m->getSegment(SegmentType::ChordRest, measure->tick());
2138                                                 st->setParent(s);
2139                                                 st->setTrack(stave);
2140                                                 score->addElement(st);
2141                                                 }
2142                                           }
2143                                     }
2144                               else if (measureCounter > 0 && bars[measureCounter - 1].freeTime) {
2145                                     TimeSig* ts = new TimeSig(score);
2146                                     ts->setSig(bars[measureCounter].timesig);
2147                                     ts->setTrack(stave);
2148                                     Measure* m = score->getCreateMeasure(measure->tick());
2149                                     Segment* s = m->getSegment(SegmentType::TimeSig, measure->tick());
2150                                     ts->setLargeParentheses(false);
2151                                     s->add(ts);
2152                                     }
2153                               else
2154                                     measure->setTimesig(bars[measureCounter].timesig);
2155                               measure->setTicks(bars[measureCounter].timesig);
2156                               }
2157 
2158                         if (!bars[measureCounter].direction.compare("Fine") || (bars[measureCounter].direction.compare("") && !bars[measureCounter].directionStyle.compare("Jump"))) {
2159                               Segment* s    = measure->getSegment(SegmentType::KeySig, measure->tick());
2160                               StaffText* st = new StaffText(score);
2161                               if (!bars[measureCounter].direction.compare("Fine"))
2162                                     st->setXmlText("fine");
2163                               else if (!bars[measureCounter].direction.compare("DaCapo"))
2164                                     st->setXmlText("Da Capo");
2165                               else if (!bars[measureCounter].direction.compare("DaCapoAlCoda"))
2166                                     st->setXmlText("D.C. al Coda");
2167                               else if (!bars[measureCounter].direction.compare("DaCapoAlDoubleCoda"))
2168                                     st->setXmlText("D.C. al Double Coda");
2169                               else if (!bars[measureCounter].direction.compare("DaCapoAlFine"))
2170                                     st->setXmlText("D.C. al Fine");
2171                               else if (!bars[measureCounter].direction.compare("DaSegnoAlCoda"))
2172                                     st->setXmlText("D.S. al Coda");
2173                               else if (!bars[measureCounter].direction.compare("DaSegno"))
2174                                     st->setXmlText("Da Segno");
2175                               else if (!bars[measureCounter].direction.compare("DaSegnoAlDoubleCoda"))
2176                                     st->setXmlText("D.S. al Double Coda");
2177                               else if (!bars[measureCounter].direction.compare("DaSegnoAlFine"))
2178                                     st->setXmlText("D.S. al Fine");
2179                               else if (!bars[measureCounter].direction.compare("DaSegnoSegno"))
2180                                     st->setXmlText("Da Segno Segno");
2181                               else if (!bars[measureCounter].direction.compare("DaSegnoSegnoAlCoda"))
2182                                     st->setXmlText("D.S.S. al Coda");
2183                               else if (!bars[measureCounter].direction.compare("DaSegnoSegnoAlDoubleCoda"))
2184                                     st->setXmlText("D.S.S. al Double Coda");
2185                               else if (!bars[measureCounter].direction.compare("DaSegnoSegnoAlFine"))
2186                                     st->setXmlText("D.S.S. al Fine");
2187                               else if (!bars[measureCounter].direction.compare("DaCoda"))
2188                                     st->setXmlText("Da Coda");
2189                               else if (!bars[measureCounter].direction.compare("DaDoubleCoda"))
2190                                     st->setXmlText("Da Double Coda");
2191                               st->setParent(s);
2192                               st->setTrack(stave);
2193                               score->addElement(st);
2194                               bars[measureCounter].direction = "";
2195                               }
2196                         else if (bars[measureCounter].direction.compare("") && !bars[measureCounter].directionStyle.compare("Target")) {
2197                               Segment* s  = measure->getSegment(SegmentType::BarLine, measure->tick());
2198                               Symbol* sym = new Symbol(score);
2199                               if (!bars[measureCounter].direction.compare("Segno"))
2200                                     sym->setSym(SymId::segno);
2201                               else if (!bars[measureCounter].direction.compare("SegnoSegno")) {
2202                                     sym->setSym(SymId::segno);
2203                                     Segment* s2  = measure->getSegment(SegmentType::ChordRest, measure->tick());
2204                                     Symbol* sym2 = new Symbol(score);
2205                                     sym2->setSym(SymId::segno);
2206                                     sym2->setParent(measure);
2207                                     sym2->setTrack(stave);
2208                                     s2->add(sym2);
2209                                     }
2210                               else if (!bars[measureCounter].direction.compare("Coda"))
2211                                     sym->setSym(SymId::coda);
2212                               else if (!bars[measureCounter].direction.compare("DoubleCoda")) {
2213                                     sym->setSym(SymId::coda);
2214                                     Segment* s2  = measure->getSegment(SegmentType::ChordRest, measure->tick());
2215                                     Symbol* sym2 = new Symbol(score);
2216                                     sym2->setSym(SymId::coda);
2217                                     sym2->setParent(measure);
2218                                     sym2->setTrack(stave);
2219                                     s2->add(sym2);
2220                                     }
2221                               sym->setParent(measure);
2222                               sym->setTrack(stave);
2223                               s->add(sym);
2224                               bars[measureCounter].direction = "";
2225                               }
2226 #if 0
2227                         if (first && measureCounter > max_counter) {
2228                               max_counter = measureCounter;
2229                               first       = false;
2230                               int counter = -1;
2231                               for (auto& dir : bars[measureCounter].directions) {
2232                                     ++counter;
2233                                     if (!dir.compare("Fine") || !bars[measureCounter].directionStyle.compare("Jump")) {
2234                                           Segment* s    = measure->getSegment(SegmentType::KeySig, measure->tick());
2235                                           StaffText* st = new StaffText(score);
2236                                           if (!dir.compare("Fine"))
2237                                                 st->setXmlText("fine");
2238                                           else if (!dir.compare("DaCapo"))
2239                                                 st->setXmlText("Da Capo");
2240                                           else if (!dir.compare("DaCapoAlCoda"))
2241                                                 st->setXmlText("D.C. al Coda");
2242                                           else if (!dir.compare("DaCapoAlDoubleCoda"))
2243                                                 st->setXmlText("D.C. al Double Coda");
2244                                           else if (!dir.compare("DaCapoAlFine"))
2245                                                 st->setXmlText("D.C. al Fine");
2246                                           else if (!dir.compare("DaSegnoAlCoda"))
2247                                                 st->setXmlText("D.S. al Coda");
2248                                           else if (!dir.compare("DaSegno"))
2249                                                 st->setXmlText("Da Segno");
2250                                           else if (!dir.compare("DaSegnoAlDoubleCoda"))
2251                                                 st->setXmlText("D.S. al Double Coda");
2252                                           else if (!dir.compare("DaSegnoAlFine"))
2253                                                 st->setXmlText("D.S. al Fine");
2254                                           else if (!dir.compare("DaSegnoSegno"))
2255                                                 st->setXmlText("Da Segno Segno");
2256                                           else if (!dir.compare("DaSegnoSegnoAlCoda"))
2257                                                 st->setXmlText("D.S.S. al Coda");
2258                                           else if (!dir.compare("DaSegnoSegnoAlDoubleCoda"))
2259                                                 st->setXmlText("D.S.S. al Double Coda");
2260                                           else if (!dir.compare("DaSegnoSegnoAlFine"))
2261                                                 st->setXmlText("D.S.S. al Fine");
2262                                           else if (!dir.compare("DaCoda"))
2263                                                 st->setXmlText("Da Coda");
2264                                           else if (!dir.compare("DaDoubleCoda"))
2265                                                 st->setXmlText("Da Double Coda");
2266                                           st->setParent(s);
2267                                           st->setTrack(stave);
2268                                           score->addElement(st);
2269                                           //bars[measureCounter].direction = "";
2270                                           }
2271                                     else if (!bars[measureCounter].directionStyle.compare("Target")) {
2272                                           Segment* s  = measure->getSegment(SegmentType::BarLine, measure->tick());
2273                                           Symbol* sym = new Symbol(score);
2274                                           if (!dir.compare("Segno"))
2275                                                 sym->setSym(SymId::segno);
2276                                           else if (!dir.compare("SegnoSegno")) {
2277                                                 sym->setSym(SymId::segnoSerpent2);
2278                                                 /* Segment* s2 = measure->getSegment(SegmentType::ChordRest, measure->tick());
2279                                                  Symbol* sym2 = new Symbol(score);
2280                                                  sym2->setSym(SymId::segno);
2281                                                  sym2->setParent(measure);
2282                                                  sym2->setTrack(stave);
2283                                                  sym2->setXoffset(5.5f);
2284                                                  sym2->setElYOffset(-7.0f * counter);
2285                                                  s2->add(sym2);*/
2286                                                 }
2287                                           else if (!dir.compare("Coda"))
2288                                                 sym->setSym(SymId::coda);
2289                                           else if (!dir.compare("DoubleCoda")) {
2290                                                 sym->setSym(SymId::codaSquare);
2291                                                 /*  Segment* s2 = measure->getSegment(SegmentType::ChordRest, measure->tick());
2292                                                   Symbol* sym2 = new Symbol(score);
2293                                                   sym2->setSym(SymId::coda);
2294                                                   sym2->setParent(measure);
2295                                                   sym2->setTrack(stave);
2296                                                   sym2->setXoffset(8.0f);
2297                                                   sym2->setElYOffset(-7.0f * counter);
2298                                                   s2->add(sym2);*/
2299                                                 }
2300                                           sym->setParent(measure);
2301                                           sym->setTrack(stave);
2302                                           s->add(sym);
2303                                           bars[measureCounter].direction = "";
2304                                           }
2305                                     }
2306                               }
2307 #endif
2308                         // we no longer set the key here, the gpbar has the information stored in it
2309                         if (!masterBarElement.nodeName().compare("Fermatas")) {
2310                               QDomNode currentFermata = masterBarElement.firstChild();
2311                               while (!currentFermata.isNull()) {
2312                                     QString fermata = currentFermata.lastChildElement("Offset").toElement().text();
2313                                     auto type       = currentFermata.lastChildElement("Type");
2314                                     currentFermata = currentFermata.nextSibling();
2315 
2316                                     // get the fermata information and construct a gpFermata from them
2317                                     QStringList fermataComponents = fermata.split("/", QString::SkipEmptyParts);
2318                                     GPFermata gpFermata;
2319                                     gpFermata.index        = fermataComponents.at(0).toInt();
2320                                     gpFermata.timeDivision = fermataComponents.at(1).toInt();
2321 
2322                                     if (!type.isNull())
2323                                           gpFermata.type = type.toElement().text();
2324                                     else
2325                                           gpFermata.type = "Medium";
2326 
2327                                     if (fermatas.contains(measureCounter)) {
2328                                           QList<GPFermata>* fermataList = fermatas.value(measureCounter);
2329                                           fermataList->push_back(gpFermata);
2330                                           }
2331                                     else {
2332                                           QList<GPFermata>* fermataList = new QList<GPFermata>;
2333                                           fermataList->push_back(gpFermata);
2334                                           fermatas.insert(measureCounter, fermataList);
2335                                           }
2336                                     }
2337                               }
2338                         else if (!masterBarElement.nodeName().compare("Repeat")) {
2339                               bool start = !masterBarElement.attributes().namedItem("start").toAttr().value().compare("true");
2340                               int count  = masterBarElement.attributes().namedItem("count").toAttr().value().toInt();
2341                               if (start)
2342                                     measure->setRepeatStart(true);
2343                               else
2344                                     measure->setRepeatEnd(true);
2345                               measure->setRepeatCount(count);
2346                               }
2347                         else if (!masterBarElement.nodeName().compare("AlternateEndings") /*&& measureCounter != last_counter2*/) {
2348                               //last_counter2 = measureCounter;
2349                               QString endNumbers = masterBarElement.toElement().text().replace(" ", ",");
2350                               bool create        = true;
2351                               if (_lastVolta) {
2352                                     auto prevm = measure->prevMeasure();
2353                                     if (prevm->endBarLineType() != BarLineType::START_REPEAT && (_lastVolta->tick2() == prevm->tick() + prevm->ticks() )
2354                                        &&(_lastVolta->text() == endNumbers) ) {
2355                                           create = false;
2356                                           _lastVolta->setTick2(measure->tick() + measure->ticks());
2357                                           }
2358                                     }
2359                               if (create) {
2360                                     Ms::Volta* volta = new Ms::Volta(score);
2361                                     volta->endings().clear();
2362                                     volta->setText(endNumbers);
2363                                     volta->setTick(measure->tick());
2364                                     volta->setTick2(measure->tick() + measure->ticks());
2365 
2366                                     const char* c = endNumbers.toUtf8().constData();
2367                                     while (c && *c)
2368                                           {
2369                                           if (*c >= '0' && *c <= '9')
2370                                                 volta->endings().push_back(int(*c - '0'));
2371                                           ++c;
2372                                           }
2373 
2374                                     _lastVolta = volta;
2375                                     score->addElement(volta);
2376                                     }
2377                               }
2378                         else if (!masterBarElement.nodeName().compare("Bars") && stave == staves - 1) {
2379                               readBars(&masterBarElement, measure, &oldClefId[0], partInfo, measureCounter);
2380                               for (int i = 0; i < staves * VOICES; ++i) {
2381                                     Ottava* o = ottava.at(i);
2382                                     if (o && o->ticks().isZero())
2383                                           o->setTick2(score->endTick());
2384                                     Slur* slur = legatos[i];
2385                                     if (slur) {
2386                                           if (measure->prevMeasure() && !measure->hasVoice(i)) {
2387                                                 //find last chord in track
2388                                                 Chord* c = nullptr;
2389                                                 for (const Segment* seg = measure->prevMeasure()->last(); seg; seg = seg->prev1()) {
2390                                                       Element* el = seg->element(i);
2391                                                       if (el && el->isChord()) {
2392                                                             c = static_cast<Chord*>(el);
2393                                                             break;
2394                                                             }
2395                                                       }
2396                                                 if (c) {
2397                                                       slur->setTick2(c->tick());
2398                                                       score->addElement(slur);
2399                                                       legatos[slur->track()] = 0;
2400                                                       }
2401                                                 }
2402                                           }
2403                                     }
2404                               }
2405                         masterBarElement = masterBarElement.nextSibling();
2406                         first = false;
2407                         }
2408                   }
2409             if (bars[measureCounter].section[0].length() || bars[measureCounter].section[1].length()) {
2410                   Segment* s = measure->getSegment(SegmentType::ChordRest, measure->tick());
2411                   if (bars[measureCounter].section[0].length()) {
2412                         RehearsalMark* t = new RehearsalMark(score);
2413                         t->setFrameType(FrameType::SQUARE);
2414                         t->setPlainText(bars[measureCounter].section[0]);
2415                         t->setTrack(0);
2416                         s->add(t);
2417                         }
2418                   if (bars[measureCounter].section[1].length()) {
2419                         RehearsalMark* t = new RehearsalMark(score);
2420                         t->setFrameType(FrameType::NO_FRAME);
2421                         t->setPlainText(bars[measureCounter].section[1]);
2422                         t->setTrack(0);
2423                         s->add(t);
2424                         }
2425                   }
2426             measureCounter++;
2427             nextMasterBar = nextMasterBar.nextSibling();
2428             measure       = measure->nextMeasure();
2429             bar++;
2430             } while (!nextMasterBar.isNull());
2431       }
2432 
2433 //---------------------------------------------------------
2434 //   readGpif
2435 //---------------------------------------------------------
2436 
readGpif(QByteArray * data)2437 void GuitarPro6::readGpif(QByteArray* data)
2438       {
2439       // qDebug() << QString(*data);
2440       QDomDocument qdomDoc;
2441       qdomDoc.setContent(*data);
2442       QDomElement qdomElem = qdomDoc.documentElement();
2443       // GPRevision node
2444       QDomNode revision = qdomElem.firstChildElement("GPRevision");
2445       // Score node
2446       QDomNode scoreNode = qdomElem.firstChildElement("Score");
2447       readScore(&scoreNode);
2448       // MasterTrack node
2449       QDomNode masterTrack = qdomElem.firstChildElement("MasterTrack");
2450       readMasterTracks(&masterTrack);
2451       // Tracks node
2452       QDomNode eachTrack = qdomElem.firstChildElement("Tracks");
2453       readTracks(&eachTrack);
2454 
2455       // now we know how many staves there are from readTracks, we can initialise slurs (for hammer/pulloff)
2456        // and legatos
2457       slurs = new Slur*[staves * VOICES];
2458       legatos = new Slur*[staves * VOICES];
2459       ottava.assign(staves * VOICES, 0);
2460       ottavaFound.assign(staves * VOICES, 0);
2461       ottavaValue.assign(staves * VOICES, "");
2462       for (int i = 0; i < staves * VOICES; ++i) {
2463             slurs[i] = 0;
2464             legatos[i] = 0;
2465             }
2466 
2467       // MasterBars node
2468       GPPartInfo partInfo;
2469       QDomNode masterBars = eachTrack.nextSibling();
2470       QDomNode b          = masterBars.nextSibling();
2471       QDomNode voices     = b.nextSibling();
2472       QDomNode beats      = voices.nextSibling();
2473       QDomNode notes      = beats.nextSibling();
2474       QDomNode rhythms    = notes.nextSibling();
2475 
2476       // set up the partInfo struct to contain information from the file
2477       partInfo.masterBars = masterBars.firstChild();
2478       partInfo.bars       = b.firstChild();
2479       partInfo.voices     = voices.firstChild();
2480       partInfo.beats      = beats.firstChild();
2481       partInfo.notes      = notes.firstChild();
2482       partInfo.rhythms    = rhythms.firstChild();
2483 
2484       measures = findNumMeasures(&partInfo);
2485 
2486       createMeasures();
2487       fermatas.clear();
2488       readMasterBars(&partInfo);
2489       // complete slurs (GP6 sometimes output destination=true even for last beat)
2490       for (int i = 0; i < staves * VOICES; ++i) {
2491             Slur* slur = legatos[i];
2492             if (slur) {
2493                   //find last chord in track
2494                   Chord* c = nullptr;
2495                   for (const Segment* seg = score->lastSegment(); seg; seg = seg->prev1()) {
2496                         Element* el = seg->element(i);
2497                         if (el && el->isChord()) {
2498                               c = static_cast<Chord*>(el);
2499                               break;
2500                               }
2501                         }
2502                   if (c) {
2503                         slur->setTick2(c->tick());
2504                         score->addElement(slur);
2505                         legatos[slur->track()] = 0;
2506                         }
2507                   else {
2508                         delete slur;
2509                         legatos[slur->track()] = 0;
2510                         }
2511                   }
2512             }
2513       // change the tuning to deal with transposition
2514       // It's needed to create correct tabs
2515       for (Part * p : score->parts()) {
2516             Instrument* instr = p->instrument();
2517             if (instr->transpose().chromatic == 0)
2518                   continue;
2519             const StringData* sd = instr->stringData();
2520             if (sd) {
2521 #if (!defined (_MSCVER) && !defined (_MSC_VER))
2522                int tuning[sd->strings()];
2523 #else
2524                // MSVC does not support VLA. Replace with std::vector. If profiling determines that the
2525                //    heap allocation is slow, an optimization might be used.
2526                std::vector<int> vTuning(sd->strings());
2527                int* tuning = vTuning.data();
2528 #endif
2529                   int frets   = sd->frets();
2530                   int strings;
2531                   for (strings = 0; strings < sd->strings(); strings++) {
2532                         tuning[strings] = sd->stringList()[strings].pitch - instr->transpose().chromatic;
2533                         }
2534                   StringData* stringData = new StringData(frets, strings, tuning);
2535                   instr->setStringData(*stringData);
2536                   }
2537             }
2538 
2539       // set the starting tempo of the score
2540       bool zero_set = false;
2541 //      int linearTemp = -1;
2542       for (auto iter = tempoMap.begin(); iter != tempoMap.end(); ++iter) {
2543             if (iter->first == 0)
2544                   zero_set = true;
2545             Measure* measure = toMeasure(score->measure(iter->first));
2546             if (measure)
2547                   setTempo(iter->second.first, measure);
2548 #if 0 // TODO-ws   what's linearTemp ?
2549             if (linearTemp != -1) {
2550                   auto siter = iter;
2551                   siter--;
2552                   auto val = iter->second.first - siter->second.first;
2553                   if (val != 0) {
2554                         for (int i = linearTemp; i <= iter->first; ++i) {
2555                               Measure* ms = toMeasure(score->measure(i));
2556                               if (ms)
2557                                     ms->setLinearTemp(val);
2558                               }
2559                         }
2560                   linearTemp = -1;
2561                   }
2562             if (iter->second.second)
2563                   linearTemp = iter->first;
2564 #endif
2565             }
2566       if (!zero_set)
2567             setTempo(120, score->firstMeasure());
2568       }
2569 
2570 //---------------------------------------------------------
2571 //   parseFile
2572 //---------------------------------------------------------
2573 
parseFile(const char * filename,QByteArray * data)2574 void GuitarPro6::parseFile(const char* filename, QByteArray* data)
2575       {
2576       // test to check if we are dealing with the score
2577       if (!strcmp(filename, "score.gpif"))
2578             readGpif(data);
2579       }
2580 
2581 //---------------------------------------------------------
2582 //   readGPX
2583 //---------------------------------------------------------
2584 
readGPX(QByteArray * buffer)2585 void GuitarPro6::readGPX(QByteArray* buffer)
2586       {
2587       // start by reading the file header. It will tell us if the byte array is compressed.
2588       int fileHeader = readInteger(buffer, 0);
2589 
2590       if (fileHeader == GPX_HEADER_COMPRESSED) {
2591             // this is  a compressed file.
2592             int length             = readInteger(buffer, position / BITS_IN_BYTE);
2593             QByteArray* bcfsBuffer = new QByteArray();
2594             int positionCounter    = 0;
2595             while(!f->error() && (position / BITS_IN_BYTE) < length) {
2596                   // read the bit indicating compression information
2597                   int flag = readBits(buffer, 1);
2598 
2599                   if (flag) {
2600                         int bits = readBits(buffer, 4);
2601                         int offs = readBitsReversed(buffer, bits);
2602                         int size = readBitsReversed(buffer, bits);
2603 
2604                         QByteArray bcfsBufferCopy = *bcfsBuffer;
2605                         int pos                   = (bcfsBufferCopy.length() - offs);
2606                         for( int i = 0; i < (size > offs ? offs : size); i++ ) {
2607                               bcfsBuffer->insert(positionCounter, bcfsBufferCopy[pos + i] );
2608                               positionCounter++;
2609                               }
2610                         }
2611                   else {
2612                         int size = readBitsReversed(buffer, 2);
2613                         for(int i = 0; i < size; i++) {
2614                               bcfsBuffer->insert(positionCounter, readBits(buffer, 8));
2615                               positionCounter++;
2616                               }
2617                         }
2618                   }
2619             // recurse on the decompressed file stored as a byte array
2620             readGPX(bcfsBuffer);
2621             delete bcfsBuffer;
2622             }
2623       else if (fileHeader == GPX_HEADER_UNCOMPRESSED) {
2624             // this is an uncompressed file - strip the header off
2625             *buffer = buffer->right(buffer->length() - sizeof(int));
2626             int sectorSize = 0x1000;
2627             int offset     = 0;
2628             while ((offset = (offset + sectorSize)) + 3 < buffer->length()) {
2629                   int newInt = readInteger(buffer,offset);
2630                   if (newInt == 2) {
2631                         int indexFileName = (offset + 4);
2632                         int indexFileSize = (offset + 0x8C);
2633                         int indexOfBlock  = (offset + 0x94);
2634 
2635                         // create a byte array and put information about files found in it
2636                         int block             = 0;
2637                         int blockCount        = 0;
2638                         QByteArray* fileBytes = new QByteArray();
2639                         while((block = (readInteger(buffer, (indexOfBlock + (4 * (blockCount++)))))) != 0 ) {
2640                               fileBytes->push_back(getBytes(buffer, (offset = (block * sectorSize)), sectorSize));
2641                               }
2642                         // get file information and read the file
2643                         int fileSize = readInteger(buffer, indexFileSize);
2644                         if (fileBytes->length() >= fileSize) {
2645                               QByteArray filenameBytes = readString(buffer, indexFileName, 127);
2646                               char* filename           = filenameBytes.data();
2647                               QByteArray data          = getBytes(fileBytes, 0, fileSize);
2648                               parseFile(filename, &data);
2649                               }
2650                         delete fileBytes;
2651                         }
2652                   }
2653             }
2654       }
2655 
2656 //---------------------------------------------------------
2657 //   readBeatEffects
2658 //---------------------------------------------------------
2659 
readBeatEffects(int,Segment *)2660 int GuitarPro6::readBeatEffects(int, Segment*)
2661       {
2662       qDebug("reading beat effects (.gpx)...\n");
2663       return 0;
2664       }
2665 
2666 //---------------------------------------------------------
2667 //   read
2668 //---------------------------------------------------------
2669 
read(QFile * fp)2670 bool GuitarPro6::read(QFile* fp)
2671       {
2672       f = fp;
2673       previousTempo = -1;
2674       QByteArray buffer = fp->readAll();
2675 
2676       // decompress and read files contained within GPX file
2677       readGPX(&buffer);
2678 
2679       return true;
2680       }
2681 }
2682