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(¤tItem, 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 ¤tVoice : 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