Line data Source code
1 : /*
2 : * SPDX-License-Identifier: GPL-3.0-only
3 : * MuseScore-Studio-CLA-applies
4 : *
5 : * MuseScore Studio
6 : * Music Composition & Notation
7 : *
8 : * Copyright (C) 2021 MuseScore Limited and others
9 : *
10 : * This program is free software: you can redistribute it and/or modify
11 : * it under the terms of the GNU General Public License version 3 as
12 : * published by the Free Software Foundation.
13 : *
14 : * This program is distributed in the hope that it will be useful,
15 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : * GNU General Public License for more details.
18 : *
19 : * You should have received a copy of the GNU General Public License
20 : * along with this program. If not, see <https://www.gnu.org/licenses/>.
21 : */
22 :
23 : #include "importgtp.h"
24 :
25 : #include <cmath>
26 :
27 : #include "importptb.h"
28 : #include "internal/guitarprodrumset.h"
29 : #include "utils.h"
30 :
31 : #include "engraving/dom/arpeggio.h"
32 : #include "engraving/dom/articulation.h"
33 : #include "engraving/dom/barline.h"
34 : #include "engraving/dom/bend.h"
35 : #include "engraving/dom/box.h"
36 : #include "engraving/dom/bracket.h"
37 : #include "engraving/dom/chord.h"
38 : #include "engraving/dom/chordline.h"
39 : #include "engraving/dom/clef.h"
40 : #include "engraving/dom/dynamic.h"
41 : #include "engraving/dom/excerpt.h"
42 : #include "engraving/dom/factory.h"
43 : #include "engraving/dom/fret.h"
44 : #include "engraving/dom/glissando.h"
45 : #include "engraving/dom/harmony.h"
46 : #include "engraving/dom/instrchange.h"
47 : #include "engraving/dom/instrtemplate.h"
48 : #include "engraving/dom/keysig.h"
49 : #include "engraving/dom/lyrics.h"
50 : #include "engraving/dom/masterscore.h"
51 : #include "engraving/dom/measure.h"
52 : #include "engraving/dom/measurebase.h"
53 : #include "engraving/dom/note.h"
54 : #include "engraving/dom/notedot.h"
55 : #include "engraving/dom/part.h"
56 : #include "engraving/dom/rehearsalmark.h"
57 : #include "engraving/dom/rest.h"
58 : #include "engraving/dom/segment.h"
59 : #include "engraving/dom/slur.h"
60 : #include "engraving/dom/staff.h"
61 : #include "engraving/dom/stafftext.h"
62 : #include "engraving/dom/stafftype.h"
63 : #include "engraving/dom/stringdata.h"
64 : #include "engraving/dom/tapping.h"
65 : #include "engraving/dom/tempotext.h"
66 : #include "engraving/dom/text.h"
67 : #include "engraving/dom/textline.h"
68 : #include "engraving/dom/tie.h"
69 : #include "engraving/dom/timesig.h"
70 : #include "engraving/dom/tuplet.h"
71 : #include "engraving/dom/volta.h"
72 : #include "engraving/dom/stringtunings.h"
73 : #include "engraving/dom/capo.h"
74 : #include "engraving/rw/xmlwriter.h"
75 : #include "engraving/types/symid.h"
76 :
77 : #include "engraving/editing/editchord.h"
78 :
79 : #include "log.h"
80 :
81 : using namespace muse;
82 : using namespace muse::io;
83 : using namespace mu::engraving;
84 :
85 : namespace mu::iex::guitarpro {
86 : //---------------------------------------------------------
87 : // errmsg
88 : //---------------------------------------------------------
89 :
90 : const char* const GuitarPro::errmsg[] = {
91 : "no error",
92 : "unknown file format",
93 : "unexpected end of file",
94 : "bad number of strings",
95 : };
96 :
97 : #ifdef _MSC_VER
98 : #pragma optimize("", off)
99 : #endif
100 :
101 : //---------------------------------------------------------
102 : // GuitarPro
103 : //---------------------------------------------------------
104 :
105 295 : GuitarPro::GuitarPro(MasterScore* s, int v, const modularity::ContextPtr& iocCtx)
106 295 : : muse::Contextable(iocCtx)
107 : {
108 295 : score = s;
109 295 : version = v;
110 295 : voltaSequence = 1;
111 295 : tempo = -1;
112 295 : }
113 :
114 : //---------------------------------------------------------
115 : // skip
116 : //---------------------------------------------------------
117 :
118 5319 : void GuitarPro::skip(int64_t len)
119 : {
120 5319 : f->seek(f->pos() + len);
121 : /*char c;
122 : while (len--)
123 : read(&c, 1);*/
124 5319 : }
125 :
126 : //---------------------------------------------------------
127 : // createTuningString
128 : //---------------------------------------------------------
129 : static const std::unordered_map<uint64_t, std::string> flatPresets = {
130 : // 63 58 54 49 44 39
131 : { 0x3f3a36312c27, { "Eb Ab Db Gb Bb Eb" } },
132 : // 60 55 51 46 41 36
133 : { 0x3c37332e2924, { "C F Bb Eb G C" } },
134 : // 63 58 54 49 44 37
135 : { 0x3f3a36312c25, { "Db Ab Db Gb Bb Eb" } },
136 : };
137 :
138 78 : bool GuitarPro::createTuningString(int strings, int tuning[])
139 : {
140 78 : bool useFlats = false;
141 78 : const char* tune[] = { "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B" };
142 78 : std::vector<int> pitch;
143 78 : uint64_t k = 0;
144 544 : for (int i = 0; i < strings; ++i) {
145 466 : pitch.push_back(tuning[i]);
146 466 : k |= (uint64_t)tuning[i] << 8 * i;
147 : }
148 78 : if (auto preset = flatPresets.find(k); preset != flatPresets.end()) {
149 0 : tunings.push_back(preset->second);
150 0 : useFlats = true;
151 0 : return useFlats;
152 : }
153 78 : std::string t;
154 544 : for (auto i : pitch) {
155 466 : t += tune[i % 12];
156 466 : t += " ";
157 : }
158 78 : tunings.push_back(t);
159 78 : return useFlats;
160 78 : }
161 :
162 74 : void GuitarPro::initDynamics(size_t stavesNum)
163 : {
164 74 : previousDynamicByTrack.resize(stavesNum * mu::engraving::VOICES);
165 74 : std::fill(previousDynamicByTrack.begin(), previousDynamicByTrack.end(), INVALID_DYNAMIC);
166 74 : }
167 :
168 : //---------------------------------------------------------
169 : // read
170 : //---------------------------------------------------------
171 :
172 78477 : void GuitarPro::read(void* p, int64_t len)
173 : {
174 78477 : if (len == 0) {
175 996 : return;
176 : }
177 77481 : int64_t rv = f->read((uint8_t*)p, len);
178 77481 : if (rv != len) {
179 0 : assert(rv == len); //to have assert in debug and no warnings from AppVeyor in release
180 : }
181 77481 : curPos += len;
182 : }
183 :
184 : //---------------------------------------------------------
185 : // readChar
186 : //---------------------------------------------------------
187 :
188 4278 : int GuitarPro::readChar()
189 : {
190 : signed char c;
191 4278 : read(&c, 1);
192 4278 : return c;
193 : }
194 :
195 : //---------------------------------------------------------
196 : // readUInt8
197 : //---------------------------------------------------------
198 :
199 39092 : uint8_t GuitarPro::readUInt8()
200 : {
201 : uint8_t c;
202 39092 : read(&c, 1);
203 39092 : return c;
204 : }
205 :
206 : //---------------------------------------------------------
207 : // readPascalString
208 : //---------------------------------------------------------
209 :
210 80 : String GuitarPro::readPascalString(int n)
211 : {
212 80 : uint8_t l = readUInt8();
213 80 : std::vector<char> s(l + 1);
214 80 : read(&s[0], l);
215 80 : s[l] = 0;
216 80 : if (n - l > 0) {
217 80 : skip(n - l);
218 : }
219 80 : std::string_view sw(&s[0], l);
220 80 : if (UtfCodec::isValidUtf8(sw)) {
221 80 : return String::fromUtf8(&s[0]);
222 : }
223 0 : return String::fromAscii(&s[0], l);
224 80 : }
225 :
226 : //---------------------------------------------------------
227 : // readWordPascalString
228 : //---------------------------------------------------------
229 :
230 335 : String GuitarPro::readWordPascalString()
231 : {
232 335 : int l = readInt();
233 335 : std::vector<char> c(l + 1);
234 335 : read(&c[0], l);
235 335 : c[l] = 0;
236 335 : std::string_view sw(&c[0], l);
237 335 : if (UtfCodec::isValidUtf8(sw)) {
238 335 : return String::fromUtf8(&c[0]);
239 : }
240 0 : return String::fromAscii(&c[0], l);
241 335 : }
242 :
243 : //---------------------------------------------------------
244 : // readBytePascalString
245 : //---------------------------------------------------------
246 :
247 440 : String GuitarPro::readBytePascalString()
248 : {
249 440 : int l = readUInt8();
250 440 : std::vector<char> c(l + 1);
251 440 : read(&c[0], l);
252 440 : c[l] = 0;
253 440 : std::string_view sw(&c[0], l);
254 440 : if (UtfCodec::isValidUtf8(sw)) {
255 440 : return String::fromUtf8(&c[0]);
256 : }
257 0 : return String::fromAscii(&c[0], l);
258 440 : }
259 :
260 : //---------------------------------------------------------
261 : // readDelphiString
262 : //---------------------------------------------------------
263 :
264 740 : String GuitarPro::readDelphiString()
265 : {
266 740 : int maxl = readInt();
267 740 : int l = readUInt8();
268 740 : if (maxl != l + 1 && maxl > 255) {
269 0 : ASSERT_X("readDelphiString: first word doesn't match second byte");
270 : l = maxl - 1;
271 : }
272 740 : std::vector<char> c(l + 1);
273 740 : read(&c[0], l);
274 740 : c[l] = 0;
275 1480 : return String::fromAscii(&c[0]);
276 740 : }
277 :
278 : //---------------------------------------------------------
279 : // readInt
280 : //---------------------------------------------------------
281 :
282 8378 : int GuitarPro::readInt()
283 : {
284 : uint8_t x;
285 8378 : read(&x, 1);
286 8378 : int r = x;
287 8378 : read(&x, 1);
288 8378 : r += x << 8;
289 8378 : read(&x, 1);
290 8378 : r += x << 16;
291 8378 : read(&x, 1);
292 8378 : r += x << 24;
293 8378 : return r;
294 : }
295 :
296 : //---------------------------------------------------------
297 : // addPalmMate
298 : //---------------------------------------------------------
299 :
300 930 : void GuitarPro::addPalmMute(ChordRest* cr, bool hasPalmMute)
301 : {
302 930 : m_continiousElementsBuilder->buildContiniousElement(cr, ElementType::PALM_MUTE, ContiniousElementsBuilder::ImportType::PALM_MUTE,
303 : hasPalmMute);
304 930 : }
305 :
306 : //---------------------------------------------------------
307 : // addLetRing
308 : //---------------------------------------------------------
309 :
310 930 : void GuitarPro::addLetRing(ChordRest* cr, bool hasLetRing)
311 : {
312 930 : m_continiousElementsBuilder->buildContiniousElement(cr, ElementType::LET_RING, ContiniousElementsBuilder::ImportType::LET_RING,
313 : hasLetRing);
314 930 : }
315 :
316 : //---------------------------------------------------------
317 : // addTrill
318 : //---------------------------------------------------------
319 :
320 839 : void GuitarPro::addTrill(ChordRest* cr, bool hasTrill)
321 : {
322 839 : m_continiousElementsBuilder->buildContiniousElement(cr, ElementType::TRILL, ContiniousElementsBuilder::ImportType::TRILL, hasTrill);
323 839 : }
324 :
325 : //---------------------------------------------------------
326 : // addHammerOnPullOff
327 : //---------------------------------------------------------
328 :
329 839 : void GuitarPro::addHammerOnPullOff(ChordRest* cr, bool hasHammerOnPullOff)
330 : {
331 839 : m_continiousElementsBuilder->buildContiniousElement(cr, ElementType::HAMMER_ON_PULL_OFF,
332 : ContiniousElementsBuilder::ImportType::HAMMER_ON_PULL_OFF, hasHammerOnPullOff);
333 839 : }
334 :
335 : //---------------------------------------------------------
336 : // addRasgueado
337 : //---------------------------------------------------------
338 :
339 545 : void GuitarPro::addRasgueado(ChordRest* cr, bool hasRasgueado)
340 : {
341 545 : m_continiousElementsBuilder->buildContiniousElement(cr, ElementType::RASGUEADO, ContiniousElementsBuilder::ImportType::RASGUEADO,
342 : hasRasgueado);
343 545 : }
344 :
345 : //---------------------------------------------------------
346 : // addVibratoLeftHand
347 : //---------------------------------------------------------
348 :
349 930 : void GuitarPro::addVibratoLeftHand(ChordRest* cr, bool hasVibratoLeftHand)
350 : {
351 930 : m_continiousElementsBuilder->buildContiniousElement(cr, ElementType::VIBRATO,
352 : ContiniousElementsBuilder::ImportType::VIBRATO_LEFT_HAND_SLIGHT, hasVibratoLeftHand,
353 : ContiniousElementsBuilder::VibratoSubType::LEFT_HAND_SLIGHT);
354 930 : }
355 :
356 : //---------------------------------------------------------
357 : // addVibratoWTremBar
358 : //---------------------------------------------------------
359 :
360 930 : void GuitarPro::addVibratoWTremBar(ChordRest* cr, bool hasVibratoWTremBar)
361 : {
362 930 : m_continiousElementsBuilder->buildContiniousElement(cr, ElementType::VIBRATO,
363 : ContiniousElementsBuilder::ImportType::VIBRATO_W_TREM_BAR_SLIGHT,
364 : hasVibratoWTremBar, ContiniousElementsBuilder::VibratoSubType::W_TREM_BAR_SLIGHT);
365 930 : }
366 :
367 : //---------------------------------------------------------
368 : // addHarmonicMarks
369 : //---------------------------------------------------------
370 :
371 839 : void GuitarPro::addHarmonicMarks(ChordRest* cr, bool hasHarmonicArtificial, bool hasHarmonicPinch, bool hasHarmonicTap,
372 : bool hasHarmonicSemi)
373 : {
374 839 : m_continiousElementsBuilder->buildContiniousElement(cr, ElementType::HARMONIC_MARK,
375 : ContiniousElementsBuilder::ImportType::HARMONIC_ARTIFICIAL,
376 : hasHarmonicArtificial, ContiniousElementsBuilder::HarmonicMarkSubType::ARTIFICIAL);
377 :
378 839 : m_continiousElementsBuilder->buildContiniousElement(cr, ElementType::HARMONIC_MARK,
379 : ContiniousElementsBuilder::ImportType::HARMONIC_PINCH,
380 : hasHarmonicPinch, ContiniousElementsBuilder::HarmonicMarkSubType::PINCH);
381 :
382 839 : m_continiousElementsBuilder->buildContiniousElement(cr, ElementType::HARMONIC_MARK,
383 : ContiniousElementsBuilder::ImportType::HARMONIC_TAP,
384 : hasHarmonicTap, ContiniousElementsBuilder::HarmonicMarkSubType::TAP);
385 :
386 839 : m_continiousElementsBuilder->buildContiniousElement(cr, ElementType::HARMONIC_MARK,
387 : ContiniousElementsBuilder::ImportType::HARMONIC_SEMI,
388 : hasHarmonicSemi, ContiniousElementsBuilder::HarmonicMarkSubType::SEMI);
389 839 : }
390 :
391 : //---------------------------------------------------------
392 : // addTap
393 : //---------------------------------------------------------
394 :
395 1 : void GuitarPro::addTap(Chord* chord)
396 : {
397 1 : Tapping* tapping = Factory::createTapping(chord);
398 1 : tapping->setTrack(chord->track());
399 1 : tapping->setHand(TappingHand::RIGHT);
400 1 : chord->add(tapping);
401 1 : }
402 :
403 : //---------------------------------------------------------
404 : // addSlap
405 : //---------------------------------------------------------
406 :
407 4 : void GuitarPro::addSlap(Note* note)
408 : {
409 4 : addTextArticulation(note, ArticulationTextType::SLAP);
410 4 : }
411 :
412 : //---------------------------------------------------------
413 : // addPop
414 : //---------------------------------------------------------
415 :
416 4 : void GuitarPro::addPop(Note* note)
417 : {
418 4 : addTextArticulation(note, ArticulationTextType::POP);
419 4 : }
420 :
421 8 : void GuitarPro::addTextArticulation(Note* note, ArticulationTextType type)
422 : {
423 8 : if (type == ArticulationTextType::NO_TEXT) {
424 0 : return;
425 : }
426 :
427 8 : if (Chord* ch = toChord(note->parent())) {
428 8 : Articulation* art = mu::engraving::Factory::createArticulation(ch);
429 8 : art->setTextType(type);
430 8 : ch->add(art);
431 : }
432 : }
433 :
434 : //---------------------------------------------------------
435 : // addTextToNote
436 : //---------------------------------------------------------
437 :
438 0 : void GuitarPro::addTextToNote(String string, Note* note)
439 : {
440 0 : Segment* segment = note->chord()->segment();
441 0 : StaffText* text = Factory::createStaffText(segment);
442 :
443 0 : if (!string.isEmpty()) {
444 0 : bool useHarmony = string[string.size() - 1] == '\\';
445 0 : if (useHarmony) {
446 0 : string.chop(1);
447 : }
448 : }
449 0 : text->setPlainText(string);
450 0 : text->setTrack(note->chord()->track());
451 0 : segment->add(text);
452 0 : }
453 :
454 0 : void GuitarPro::setupTupletStyle(Tuplet* tuplet)
455 : {
456 : bool real;
457 0 : switch (tuplet->ratio().numerator()) {
458 0 : case 2: real = (tuplet->ratio().denominator() == 3);
459 0 : break;
460 0 : case 3:
461 0 : case 4: real = (tuplet->ratio().denominator() == 2);
462 0 : break;
463 0 : case 5:
464 : case 6:
465 0 : case 7: real = (tuplet->ratio().denominator() == 4);
466 0 : break;
467 0 : case 9:
468 : case 10:
469 : case 11:
470 : case 12:
471 0 : case 13: real = (tuplet->ratio().denominator() == 8);
472 0 : break;
473 0 : default: real = false;
474 : }
475 0 : if (!real) {
476 0 : tuplet->setNumberType(TupletNumberType::SHOW_RELATION);
477 0 : tuplet->setPropertyFlags(Pid::NUMBER_TYPE, PropertyFlags::UNSTYLED);
478 : }
479 0 : }
480 :
481 : //---------------------------------------------------------
482 : // setTuplet
483 : //---------------------------------------------------------
484 :
485 20 : void GuitarPro::setTuplet(Tuplet* tuplet, int tuple)
486 : {
487 20 : switch (tuple) {
488 20 : case 3:
489 20 : tuplet->setRatio(Fraction(3, 2));
490 20 : break;
491 0 : case 5:
492 0 : tuplet->setRatio(Fraction(5, 4));
493 0 : break;
494 0 : case 6:
495 0 : tuplet->setRatio(Fraction(6, 4));
496 0 : break;
497 0 : case 7:
498 0 : tuplet->setRatio(Fraction(7, 4));
499 0 : break;
500 0 : case 9:
501 0 : tuplet->setRatio(Fraction(9, 8));
502 0 : break;
503 0 : case 10:
504 0 : tuplet->setRatio(Fraction(10, 8));
505 0 : break;
506 0 : case 11:
507 0 : tuplet->setRatio(Fraction(11, 8));
508 0 : break;
509 0 : case 12:
510 0 : tuplet->setRatio(Fraction(12, 8));
511 0 : break;
512 0 : case 13:
513 0 : tuplet->setRatio(Fraction(13, 8));
514 0 : break;
515 0 : default:
516 0 : ASSERT_X(String(u"unsupported tuplet %d\n").arg(tuple));
517 : }
518 20 : }
519 :
520 : //---------------------------------------------------------
521 : // addDynamic
522 : //---------------------------------------------------------
523 :
524 148 : void GuitarPro::addDynamic(Note* note, int d)
525 : {
526 : // guitar pro only allows their users to go from ppp to fff
527 148 : static const std::array<String, 9> map_dyn { u"f", u"ppp", u"pp", u"p", u"mp", u"mf", u"f", u"ff", u"fff" };
528 296 : if (d < 0 || static_cast<size_t>(d) >= map_dyn.size()) {
529 2 : return;
530 : }
531 146 : if (!note->chord()) {
532 0 : LOGD() << "addDynamics: No chord associated with this note";
533 0 : return;
534 : }
535 146 : Segment* s = nullptr;
536 146 : if (note->chord()->isGrace()) {
537 0 : Chord* parent = toChord(note->chord()->parent());
538 0 : s = parent->segment();
539 : } else {
540 146 : s = note->chord()->segment();
541 : }
542 146 : if (!s->findAnnotation(ElementType::DYNAMIC, note->staffIdx() * VOICES, note->staffIdx() * VOICES + VOICES - 1)) {
543 111 : Dynamic* dyn = new Dynamic(s);
544 111 : dyn->setDynamicType(map_dyn[d]);
545 111 : dyn->setTrack(note->track());
546 111 : s->add(dyn);
547 : }
548 : }
549 :
550 : //---------------------------------------------------------
551 : // readVolta
552 : //---------------------------------------------------------
553 :
554 234 : void GuitarPro::readVolta(GPVolta* gpVolta, Measure* m)
555 : {
556 : /* Volta information is at most eight bits
557 : * signifying which numbers should appear in the
558 : * volta. A single bit 1 represents we should show
559 : * 1, 100 represents 3, 10000 represents 6, 10101
560 : * represents 1,3,5 etc. */
561 234 : if (gpVolta->voltaInfo.size() != 0) {
562 : // we have volta information - set up a volta
563 16 : mu::engraving::Volta* volta = new mu::engraving::Volta(score->dummy());
564 16 : volta->endings().clear();
565 16 : String voltaTextString = u"";
566 : // initialise count to 1 as the first bit processed with represent first time volta
567 16 : int count = 0;
568 16 : int binaryNumber = 0;
569 : // iterate through the volta information and determine the decimal numbers for voltas
570 16 : auto iter = gpVolta->voltaInfo.begin();
571 77 : while (iter != gpVolta->voltaInfo.end()) {
572 45 : switch (gpVolta->voltaType) {
573 9 : case GP_VOLTA_FLAGS:
574 9 : count++;
575 9 : if (*iter == 1) { // we want this number to be displayed in the volta
576 5 : if (voltaTextString.empty()) {
577 2 : voltaTextString += String::number(count);
578 : } else {
579 3 : voltaTextString += u',' + String::number(count);
580 : }
581 : // add the decimal number to the endings field of voltas as well as the text
582 5 : volta->endings().push_back(count);
583 : }
584 9 : ++iter;
585 9 : break;
586 36 : case GP_VOLTA_BINARY:
587 : // find the binary number in decimal
588 36 : if (*iter == 1) {
589 20 : binaryNumber += pow(2, count);
590 : }
591 36 : ++iter;
592 36 : if (iter == gpVolta->voltaInfo.end()) {
593 : // display all numbers in the volta from voltaSequence to the decimal
594 42 : while (voltaSequence <= binaryNumber) {
595 28 : if (voltaTextString.empty()) {
596 14 : voltaTextString = String::number(voltaSequence);
597 : } else {
598 14 : voltaTextString += u',' + String::number(voltaSequence);
599 : }
600 28 : volta->endings().push_back(voltaSequence);
601 28 : voltaSequence++;
602 : }
603 : }
604 36 : count++;
605 36 : break;
606 : }
607 : }
608 16 : volta->setText(XmlWriter::xmlString(voltaTextString));
609 16 : volta->setTick(m->tick());
610 16 : volta->setTick2(m->endTick());
611 16 : score->addElement(volta);
612 16 : }
613 234 : }
614 :
615 22 : std::vector<PitchValue> GuitarPro::readBendDataFromFile()
616 : {
617 22 : std::vector<PitchValue> bendData;
618 :
619 22 : readUInt8(); // icon
620 22 : /*int amplitude =*/ readInt(); // shown amplitude
621 22 : int numPoints = readInt(); // the number of points in the bend
622 :
623 105 : for (int i = 0; i < numPoints; ++i) {
624 83 : int bendTime = readInt();
625 83 : int bendPitch = readInt();
626 83 : int bendVibrato = readUInt8();
627 83 : bendData.emplace_back(bendTime, bendPitch, bendVibrato);
628 : }
629 :
630 22 : return bendData;
631 0 : }
632 :
633 22 : void GuitarPro::createBend(Note* note, std::vector<PitchValue>& bendData)
634 : {
635 22 : if (bendData.size() < 2) {
636 0 : return;
637 : }
638 :
639 : /// not adding "hold" on 0 pitch
640 22 : int maxPitch = (std::max_element(bendData.begin(), bendData.end(), [](const PitchValue& l, const PitchValue& r) {
641 61 : return l.pitch < r.pitch;
642 22 : }))->pitch;
643 :
644 22 : if (maxPitch == 0) {
645 0 : return;
646 : }
647 :
648 22 : m_guitarBendImporter->collectBend(note, bendData);
649 : }
650 :
651 : //---------------------------------------------------------
652 : // readBend
653 : // bend graph
654 : //---------------------------------------------------------
655 :
656 10 : void GuitarPro::readBend(Note* note)
657 : {
658 10 : std::vector<PitchValue> bendData = readBendDataFromFile();
659 10 : createBend(note, bendData);
660 10 : }
661 :
662 : //---------------------------------------------------------
663 : // readLyrics
664 : //---------------------------------------------------------
665 :
666 67 : void GuitarPro::readLyrics()
667 : {
668 67 : gpLyrics.lyricTrack = static_cast<size_t>(readInt()); // lyric track
669 67 : gpLyrics.fromBeat = static_cast<size_t>(readInt());
670 67 : gpLyrics.beatCounter = 0;
671 :
672 67 : String lyrics = readWordPascalString();
673 67 : lyrics.replace(u'\n', u' ');
674 67 : lyrics.replace(u'\r', u' ');
675 67 : auto sl = lyrics.split(u' ', KeepEmptyParts);
676 134 : for (auto& str : sl) {
677 67 : gpLyrics.lyrics.push_back(str);
678 : }
679 :
680 335 : for (int i = 0; i < 4; ++i) {
681 268 : readInt();
682 268 : readWordPascalString();
683 : }
684 67 : }
685 :
686 : //---------------------------------------------------------
687 : // createSlide
688 : //---------------------------------------------------------
689 :
690 16 : void GuitarPro::createSlide(int sl, ChordRest* cr, int staffIdx, Note* note)
691 : {
692 : UNUSED(note);
693 : // shift / legato slide
694 16 : if (sl == SHIFT_SLIDE || sl == LEGATO_SLIDE) {
695 0 : Glissando* s = mu::engraving::Factory::createGlissando(cr);
696 : //s->setXmlText("");
697 0 : s->setGlissandoType(GlissandoType::STRAIGHT);
698 0 : cr->add(s);
699 0 : Segment* prevSeg = cr->segment()->prev1(SegmentType::ChordRest);
700 0 : EngravingItem* prevElem = prevSeg->element(staffIdx);
701 0 : if (prevElem) {
702 0 : if (prevElem->isChord()) {
703 0 : Chord* prevChord = toChord(prevElem);
704 : /** TODO we should not just take the top note here
705 : * but the /correct/ note need to check whether GP
706 : * supports multi-note gliss. I think it can in modern
707 : * versions */
708 0 : s->setStartElement(prevChord->upNote());
709 0 : s->setTick(prevSeg->tick());
710 0 : s->setTrack(staffIdx);
711 0 : s->setOwnershipParent(prevChord->upNote());
712 0 : s->setText(u"");
713 0 : s->setGlissandoType(GlissandoType::STRAIGHT);
714 0 : s->setGlissandoShift(sl == SHIFT_SLIDE);
715 0 : s->setGlissandoStyle(s->part()->instrument(s->tick())->glissandoStyle());
716 :
717 0 : if (sl == LEGATO_SLIDE) {
718 0 : createSlur(true, staffIdx, prevChord);
719 : }
720 : }
721 : }
722 :
723 0 : Chord* chord = (Chord*)cr;
724 : /* TODO again here, we should not just set the up note but the
725 : * /correct/ note need to check whether GP supports
726 : * multi-note gliss. I think it can in modern versions */
727 0 : s->setEndElement(chord->upNote());
728 0 : s->setTick2(chord->segment()->tick());
729 0 : s->setTrack2(staffIdx);
730 0 : score->addElement(s);
731 0 : if (sl == LEGATO_SLIDE) {
732 0 : createSlur(false, staffIdx, cr);
733 : }
734 : }
735 : // slide out downwards (fall)
736 16 : if (sl & SLIDE_OUT_DOWN) {
737 4 : ChordLine* sld = Factory::createChordLine(mu::engraving::toChord(cr));
738 4 : sld->setChordLineType(ChordLineType::FALL);
739 4 : cr->add(sld);
740 : }
741 : // slide out upwards (doit)
742 16 : if (sl & SLIDE_OUT_UP) {
743 4 : ChordLine* slu = Factory::createChordLine(mu::engraving::toChord(cr));
744 4 : slu->setChordLineType(ChordLineType::DOIT);
745 4 : cr->add(slu);
746 : }
747 : // slide in from below (plop)
748 16 : if (sl & SLIDE_IN_BELOW) {
749 4 : ChordLine* slb = Factory::createChordLine(mu::engraving::toChord(cr));
750 4 : slb->setChordLineType(ChordLineType::PLOP);
751 4 : cr->add(slb);
752 : }
753 : // slide in from above (scoop)
754 16 : if (sl & SLIDE_IN_ABOVE) {
755 4 : ChordLine* sla = Factory::createChordLine(mu::engraving::toChord(cr));
756 4 : sla->setChordLineType(ChordLineType::SCOOP);
757 4 : cr->add(sla);
758 : }
759 16 : }
760 :
761 : //---------------------------------------------------------
762 : // readChannels
763 : //---------------------------------------------------------
764 :
765 67 : void GuitarPro::readChannels()
766 : {
767 4355 : for (int i = 0; i < GP_MAX_TRACK_NUMBER * 2; ++i) {
768 4288 : channelDefaults[i].patch = readInt();
769 4288 : channelDefaults[i].volume = readUInt8() * 8 - 1;
770 4288 : channelDefaults[i].pan = readUInt8() * 8 - 1;
771 4288 : channelDefaults[i].chorus = readUInt8() * 8 - 1;
772 4288 : channelDefaults[i].reverb = readUInt8() * 8 - 1;
773 4288 : channelDefaults[i].phase = readUInt8() * 8 - 1;
774 4288 : channelDefaults[i].tremolo = readUInt8() * 8 - 1;
775 :
776 : // defaults of 255, or any value above 127, are set to 0 (Musescore range is 0-127)
777 4288 : if (channelDefaults[i].patch > 127) {
778 0 : channelDefaults[i].patch = 0;
779 : }
780 4288 : if (channelDefaults[i].volume > 127) {
781 2470 : channelDefaults[i].volume = 0;
782 : }
783 4288 : if (channelDefaults[i].pan > 127) {
784 2470 : channelDefaults[i].pan = 0;
785 : }
786 4288 : if (channelDefaults[i].chorus > 127) {
787 4288 : channelDefaults[i].chorus = 0;
788 : }
789 4288 : if (channelDefaults[i].reverb > 127) {
790 4288 : channelDefaults[i].reverb = 0;
791 : }
792 4288 : if (channelDefaults[i].phase > 127) {
793 4288 : channelDefaults[i].phase = 0;
794 : }
795 4288 : if (channelDefaults[i].tremolo > 127) {
796 4288 : channelDefaults[i].tremolo = 0;
797 : }
798 :
799 : // skip over blank information included for backwards compatibility with 3.0
800 4288 : skip(2);
801 : }
802 67 : }
803 :
804 : //---------------------------------------------------------
805 : // len2fraction
806 : //---------------------------------------------------------
807 :
808 1083 : Fraction GuitarPro::len2fraction(int len)
809 : {
810 1083 : Fraction l;
811 1083 : switch (len) {
812 24 : case -2: l.set(1, 1);
813 24 : break;
814 115 : case -1: l.set(1, 2);
815 115 : break;
816 778 : case 0: l.set(1, 4);
817 778 : break;
818 119 : case 1: l.set(1, 8);
819 119 : break;
820 47 : case 2: l.set(1, 16);
821 47 : break;
822 0 : case 3: l.set(1, 32);
823 0 : break;
824 0 : case 4: l.set(1, 64);
825 0 : break;
826 0 : case 5: l.set(1, 128);
827 0 : break;
828 : // set to len - in some cases we get whacky numbers for this (40, 28...)
829 0 : default:
830 0 : l.set(1, len);
831 : }
832 1083 : return l;
833 : }
834 :
835 : //---------------------------------------------------------
836 : // readMixChange
837 : //---------------------------------------------------------
838 :
839 1 : bool GuitarPro::readMixChange(Measure* measure)
840 : {
841 : /*char patch =*/
842 1 : readChar();
843 1 : signed char volume = readChar();
844 1 : signed char pan = readChar();
845 1 : signed char chorus = readChar();
846 1 : signed char reverb = readChar();
847 1 : signed char phase = readChar();
848 1 : signed char tremolo = readChar();
849 1 : int temp = readInt();
850 :
851 1 : if (volume >= 0) {
852 0 : readChar();
853 : }
854 1 : if (pan >= 0) {
855 0 : readChar();
856 : }
857 1 : if (chorus >= 0) {
858 0 : readChar();
859 : }
860 1 : if (reverb >= 0) {
861 0 : readChar();
862 : }
863 1 : if (phase >= 0) {
864 0 : readChar();
865 : }
866 1 : if (tremolo >= 0) {
867 0 : readChar();
868 : }
869 1 : if (temp >= 0) {
870 1 : if (temp != previousTempo) {
871 1 : previousTempo = temp;
872 1 : setTempo(temp, measure);
873 : }
874 1 : readChar();
875 : }
876 1 : return true;
877 : }
878 :
879 : //---------------------------------------------------------
880 : // createMeasures
881 : //---------------------------------------------------------
882 :
883 67 : void GuitarPro::createMeasures()
884 : {
885 67 : Fraction tick = Fraction(0, 1);
886 67 : Fraction ts;
887 67 : LOGD("measures %zu bars.size %zu", measures, bars.size());
888 :
889 : // for (int i = 0; i < measures; ++i) {
890 278 : for (size_t i = 0; i < bars.size(); ++i) { // ?? (ws)
891 211 : Fraction nts = bars[i].timesig;
892 211 : Measure* m = Factory::createMeasure(score);
893 211 : m->setTick(tick);
894 211 : m->setTimesig(nts);
895 211 : m->setTicks(nts);
896 :
897 211 : if (i == 0 || ts.numerator() != nts.numerator() || ts.denominator() != nts.denominator()) {
898 139 : for (size_t staffIdx = 0; staffIdx < staves; ++staffIdx) {
899 72 : const Staff* staff = score->staff(staffIdx);
900 72 : const StaffType* staffType = staff->staffType(Fraction(0, 1)); // at tick 0
901 72 : if (staffType->genTimesig()) {
902 72 : Segment* s = m->getSegment(SegmentType::TimeSig, tick);
903 72 : TimeSig* t = Factory::createTimeSig(s);
904 72 : t->setTrack(staffIdx * VOICES);
905 72 : t->setSig(nts);
906 72 : s->add(t);
907 : }
908 : }
909 : }
910 211 : if (i == 0 || (bars[i].keysig != GP_INVALID_KEYSIG)) {
911 259 : for (size_t staffIdx = 0; staffIdx < staves; ++staffIdx) {
912 132 : int keysig = bars[i].keysig != GP_INVALID_KEYSIG ? bars[i].keysig : key;
913 132 : if (tick.isZero() || (int)score->staff(staffIdx)->key(tick) != (int)Key(keysig)) {
914 132 : Segment* s = m->getSegment(SegmentType::KeySig, tick);
915 132 : KeySig* t = Factory::createKeySig(s);
916 132 : t->setKey(Key(keysig));
917 132 : t->setTrack(staffIdx * VOICES);
918 132 : s->add(t);
919 : }
920 : }
921 : }
922 211 : readVolta(&bars[i].volta, m);
923 211 : m->setRepeatEnd(bars[i].repeatFlags == mu::engraving::Repeat::END);
924 211 : m->setRepeatStart(bars[i].repeatFlags == mu::engraving::Repeat::START);
925 211 : m->setRepeatJump(bars[i].repeatFlags == mu::engraving::Repeat::JUMP);
926 : // m->setRepeatFlags(bars[i].repeatFlags);
927 211 : m->setRepeatCount(bars[i].repeats); // supported in gp5
928 :
929 211 : if (bars[i].repeatFlags == (mu::engraving::Repeat::START | mu::engraving::Repeat::END)) {
930 0 : m->setRepeatEnd(true);
931 0 : m->setRepeatStart(true);
932 0 : voltaSequence = 1;
933 : }
934 : // reset the volta sequence if we have an opening repeat
935 211 : if (bars[i].repeatFlags == mu::engraving::Repeat::START) {
936 1 : voltaSequence = 1;
937 : }
938 : // otherwise, if we see an end repeat symbol, only reset if the bar after it does not contain a volta
939 210 : else if (bars[i].repeatFlags == mu::engraving::Repeat::END && i < bars.size() - 1) {
940 3 : if (bars[i + 1].volta.voltaInfo.size() == 0) {
941 1 : voltaSequence = 1; // reset the volta count
942 : }
943 : }
944 :
945 211 : score->measures()->append(m);
946 211 : tick += nts;
947 211 : ts = nts;
948 : }
949 67 : }
950 :
951 : //---------------------------------------------------------
952 : // applyBeatEffects
953 : //---------------------------------------------------------
954 :
955 797 : void GuitarPro::applyBeatEffects(Chord* chord, int beatEffect, bool& hasVibratoLeftHand, bool& hasVibratoWTremBar)
956 : {
957 : /* slap/pop implemented as text until SMuFL has
958 : * specifications and we can add them to fonts. Note that
959 : * slap/pop are just added to the top note in the chord,
960 : * technically these can be applied to individual notes on the
961 : * UI, but Guitar Pro has no way to express that on the
962 : * score. To get the same result, we should just add the marking
963 : * to above the top note.
964 : */
965 797 : if (beatEffect == 1) {
966 1 : if (version > 300) {
967 1 : addTap(chord);
968 : } else {
969 0 : hasVibratoLeftHand = true;
970 : }
971 796 : } else if (beatEffect == 2) {
972 4 : addSlap(chord->upNote());
973 792 : } else if (beatEffect == 3) {
974 4 : addPop(chord->upNote());
975 788 : } else if (beatEffect == 4) {
976 2 : if (version >= 400) {
977 2 : Articulation* a = Factory::createArticulation(chord);
978 2 : a->setSymId(SymId::guitarFadeIn);
979 2 : a->setAnchor(ArticulationAnchor::TOP);
980 2 : a->setPropertyFlags(Pid::ARTICULATION_ANCHOR, PropertyFlags::UNSTYLED);
981 2 : chord->add(a);
982 : }
983 : //TODO-ws else for (auto n : chord->notes())
984 : // n->setHarmonic(true);
985 786 : } else if (beatEffect == 5) {
986 2 : Articulation* a = Factory::createArticulation(chord);
987 2 : a->setSymId(SymId::stringsUpBow);
988 2 : chord->add(a);
989 784 : } else if (beatEffect == 6) {
990 2 : Articulation* art = Factory::createArticulation(chord);
991 2 : art->setSymId(SymId::stringsDownBow);
992 2 : chord->add(art);
993 782 : } else if (beatEffect == 7) {
994 6 : hasVibratoWTremBar = true;
995 : }
996 797 : }
997 :
998 : #ifdef _MSC_VER
999 : #pragma optimize("", on)
1000 : #endif
1001 :
1002 : //---------------------------------------------------------
1003 : // read
1004 : //---------------------------------------------------------
1005 :
1006 0 : bool GuitarPro1::read(IODevice* io)
1007 : {
1008 0 : m_continiousElementsBuilder = std::make_unique<ContiniousElementsBuilder>(score);
1009 0 : m_guitarBendImporter = std::make_unique<GuitarBendImporter>(score);
1010 :
1011 0 : f = io;
1012 0 : curPos = 30;
1013 :
1014 0 : title = readDelphiString();
1015 0 : artist = readDelphiString();
1016 0 : readDelphiString();
1017 :
1018 0 : int temp = readInt();
1019 0 : /*uint8_t num =*/ readUInt8(); // Shuffle rhythm feel
1020 :
1021 : // int octave = 0;
1022 0 : key = 0;
1023 0 : if (version > 102) {
1024 0 : key = readInt(); // key
1025 : }
1026 0 : staves = version > 102 ? 8 : 1;
1027 0 : slurs.resize(staves, nullptr);
1028 :
1029 : //
1030 : // create a part for every staff
1031 : //
1032 0 : for (size_t staffIdx = 0; staffIdx < staves; ++staffIdx) {
1033 0 : Part* part = new Part(score);
1034 0 : Staff* s = Factory::createStaff(part);
1035 :
1036 0 : score->appendStaff(s);
1037 0 : score->appendPart(part);
1038 : }
1039 :
1040 0 : for (size_t i = 0; i < staves; ++i) {
1041 : int tuning[GP_MAX_STRING_NUMBER];
1042 :
1043 0 : int strings = version > 101 ? readInt() : 6;
1044 0 : if (strings <= 0 || strings > GP_MAX_STRING_NUMBER) {
1045 0 : return false;
1046 : }
1047 :
1048 0 : for (int j = 0; j < strings; ++j) {
1049 0 : tuning[j] = readInt();
1050 : }
1051 0 : std::vector<int> tuning2(strings);
1052 0 : for (int k = 0; k < strings; ++k) {
1053 0 : tuning2[strings - k - 1] = tuning[k];
1054 : }
1055 :
1056 0 : int frets = 32; // TODO
1057 0 : bool useFlats = createTuningString(strings, &tuning2[0]);
1058 0 : StringData stringData(frets, strings, &tuning2[0], useFlats);
1059 0 : Part* part = score->staff(i)->part();
1060 0 : Instrument* instr = part->instrument();
1061 0 : instr->setStringData(stringData);
1062 0 : instr->setSingleNoteDynamics(false);
1063 0 : }
1064 :
1065 0 : measures = readInt();
1066 :
1067 0 : Fraction ts;
1068 0 : Fraction tick = { 0, 1 };
1069 0 : for (size_t i = 0; i < measures; ++i) {
1070 0 : Fraction nts = bars[i].timesig;
1071 0 : Measure* m = Factory::createMeasure(score);
1072 0 : m->setTick(tick);
1073 0 : m->setTimesig(nts);
1074 0 : m->setTicks(nts);
1075 :
1076 0 : if (i == 0 || ts != nts) {
1077 0 : for (size_t staffIdx = 0; staffIdx < staves; ++staffIdx) {
1078 0 : Segment* s = m->getSegment(SegmentType::TimeSig, tick);
1079 0 : TimeSig* t = Factory::createTimeSig(s);
1080 0 : t->setTrack(staffIdx * VOICES);
1081 0 : t->setSig(nts);
1082 0 : s->add(t);
1083 : }
1084 : }
1085 :
1086 0 : score->measures()->append(m);
1087 0 : tick += nts;
1088 0 : ts = nts;
1089 : }
1090 :
1091 0 : previousTempo = temp;
1092 0 : Measure* measure = score->firstMeasure();
1093 0 : bool mixChange = false;
1094 0 : for (size_t bar = 0; bar < measures; ++bar, measure = measure->nextMeasure()) {
1095 0 : const GpBar& gpbar = bars[bar];
1096 :
1097 0 : if (!gpbar.marker.isEmpty()) {
1098 0 : Segment* segment = measure->getSegment(SegmentType::ChordRest, measure->tick());
1099 0 : RehearsalMark* s = new RehearsalMark(segment);
1100 0 : s->setPlainText(gpbar.marker.trimmed());
1101 0 : s->setTrack(0);
1102 0 : segment->add(s);
1103 : }
1104 0 : std::vector<Tuplet*> tuplets(staves);
1105 0 : for (size_t staffIdx = 0; staffIdx < staves; ++staffIdx) {
1106 0 : tuplets[staffIdx] = 0;
1107 : }
1108 :
1109 0 : for (size_t staffIdx = 0; staffIdx < staves; ++staffIdx) {
1110 0 : Fraction measureLen = { 0, 1 };
1111 0 : track_idx_t track = staffIdx * VOICES;
1112 0 : Fraction fraction = measure->tick();
1113 0 : int beats = readInt();
1114 0 : for (int beat = 0; beat < beats; ++beat) {
1115 : // int pause = 0;
1116 0 : uint8_t beatBits = readUInt8();
1117 0 : bool dotted = beatBits & BEAT_DOTTED;
1118 0 : if (beatBits & BEAT_PAUSE) {
1119 : /*pause =*/
1120 0 : readUInt8();
1121 : }
1122 0 : int len = readChar();
1123 0 : int tuple = 0;
1124 0 : if (beatBits & BEAT_TUPLET) {
1125 0 : tuple = readInt();
1126 : }
1127 0 : Segment* segment = measure->getSegment(SegmentType::ChordRest, fraction);
1128 0 : if (beatBits & BEAT_CHORD) {
1129 0 : int numStrings = static_cast<int>(score->staff(staffIdx)->part()->instrument()->stringData()->strings());
1130 0 : int header = readUInt8();
1131 0 : String name;
1132 0 : if ((header & 1) == 0) {
1133 0 : name = readDelphiString();
1134 0 : readChord(segment, static_cast<int>(track), numStrings, name, false);
1135 : } else {
1136 0 : skip(25);
1137 0 : name = readPascalString(34);
1138 0 : readChord(segment, static_cast<int>(track), numStrings, name, true);
1139 0 : skip(36);
1140 : }
1141 0 : }
1142 0 : Lyrics* lyrics = 0;
1143 0 : if (beatBits & BEAT_LYRICS) {
1144 0 : lyrics = Factory::createLyrics(score->dummy());
1145 0 : lyrics->setPlainText(readDelphiString());
1146 : }
1147 0 : if (beatBits & BEAT_EFFECTS) {
1148 0 : readBeatEffects(static_cast<int>(track), segment);
1149 : }
1150 :
1151 0 : if (beatBits & BEAT_MIX_CHANGE) {
1152 0 : readMixChange(measure);
1153 0 : mixChange = true;
1154 : }
1155 :
1156 0 : int strings = readUInt8(); // used strings mask
1157 :
1158 0 : Fraction l = len2fraction(len);
1159 : ChordRest* cr;
1160 0 : if (strings) {
1161 0 : cr = Factory::createChord(score->dummy());
1162 : } else {
1163 0 : cr = Factory::createRest(score->dummy());
1164 : }
1165 0 : cr->setTrack(track);
1166 0 : if (lyrics) {
1167 0 : cr->add(lyrics);
1168 : }
1169 :
1170 0 : TDuration d(l);
1171 0 : d.setDots(dotted ? 1 : 0);
1172 :
1173 0 : if (dotted) {
1174 0 : l = l + (l * Fraction(1, 2));
1175 : }
1176 :
1177 0 : if (tuple) {
1178 0 : Tuplet* tuplet = tuplets[staffIdx];
1179 0 : if ((tuplet == 0) || (tuplet->elementsDuration() == tuplet->baseLen().fraction() * tuplet->ratio().numerator())) {
1180 0 : tuplet = Factory::createTuplet(measure);
1181 0 : tuplet->setTick(fraction);
1182 0 : tuplet->setTrack(cr->track());
1183 0 : tuplets[staffIdx] = tuplet;
1184 0 : setTuplet(tuplet, tuple);
1185 : }
1186 0 : tuplet->setTrack(track);
1187 0 : tuplet->setBaseLen(l);
1188 0 : tuplet->setTicks(l * tuplet->ratio().denominator());
1189 0 : cr->setTuplet(tuplet);
1190 0 : tuplet->add(cr); //TODOxxx
1191 : }
1192 :
1193 0 : cr->setTicks(l);
1194 0 : cr->setDurationType(d);
1195 0 : segment->add(cr);
1196 0 : Staff* staff = cr->staff();
1197 0 : int numStrings = static_cast<int>(staff->part()->instrument()->stringData()->strings());
1198 0 : ReadNoteResult readResult;
1199 0 : bool hasLetRing = false;
1200 0 : bool hasPalmMute = false;
1201 0 : for (int i = 6; i >= 0; --i) {
1202 0 : if (strings & (1 << i) && ((6 - i) < numStrings)) {
1203 0 : Note* note = Factory::createNote(toChord(cr));
1204 0 : toChord(cr)->add(note);
1205 0 : readResult = readNote(6 - i, note);
1206 0 : hasLetRing = readResult.letRing || hasLetRing;
1207 0 : hasPalmMute = readResult.palmMute || hasPalmMute;
1208 0 : note->setTpcFromPitch();
1209 : }
1210 : }
1211 0 : restsForEmptyBeats(segment, measure, cr, l, static_cast<int>(track), fraction);
1212 0 : fraction += cr->actualTicks();
1213 0 : measureLen += cr->actualTicks();
1214 0 : addLetRing(cr, hasLetRing);
1215 0 : addPalmMute(cr, hasPalmMute);
1216 : }
1217 0 : if (measureLen < measure->ticks()) {
1218 0 : score->setRest(fraction, track, measure->ticks() - measureLen, false, nullptr, false);
1219 0 : m_continiousElementsBuilder->notifyUncompletedMeasure();
1220 : }
1221 : }
1222 0 : if (bar == 1 && !mixChange) {
1223 0 : setTempo(temp, score->firstMeasure());
1224 : }
1225 0 : }
1226 :
1227 0 : m_continiousElementsBuilder->addElementsToScore();
1228 0 : addTunings();
1229 0 : return true;
1230 : }
1231 :
1232 : //---------------------------------------------------------
1233 : // setTempo
1234 : //---------------------------------------------------------
1235 :
1236 359 : void GuitarPro::setTempo(int newTempo, Measure* measure)
1237 : {
1238 359 : if (!measure || measure == last_measure) {
1239 308 : return;
1240 : }
1241 :
1242 51 : last_measure = measure;
1243 :
1244 51 : if (last_tempo != newTempo) {
1245 51 : Segment* segment = measure->getSegment(SegmentType::ChordRest, measure->tick());
1246 51 : TempoText* tt = Factory::createTempoText(segment);
1247 51 : tt->setTempo(BeatsPerSecond::fromBPM(newTempo));
1248 51 : tt->setXmlText(String(u"<sym>metNoteQuarterUp</sym> = %1").arg(newTempo));
1249 51 : tt->setTrack(0);
1250 51 : segment->add(tt);
1251 51 : tempo = newTempo;
1252 51 : last_tempo = newTempo;
1253 : }
1254 : }
1255 :
1256 : //---------------------------------------------------------
1257 : // readChord
1258 : //---------------------------------------------------------
1259 :
1260 4 : void GuitarPro::readChord(Segment* seg, int track, int numStrings, String name, bool gpHeader)
1261 : {
1262 4 : int firstFret = readInt();
1263 4 : if (firstFret || gpHeader) {
1264 : /// showing chord instead of fret diagrams
1265 : if (true) {
1266 4 : StaffText* staffText = Factory::createStaffText(seg);
1267 4 : staffText->setTrack(track);
1268 4 : staffText->setPlainText(name);
1269 4 : seg->add(staffText);
1270 4 : skip(4 * (gpHeader ? 7 : 6));
1271 : } else {
1272 : FretDiagram* fret = Factory::createFretDiagram(seg);
1273 : fret->setTrack(track);
1274 : fret->setStrings(numStrings);
1275 : fret->setFretOffset(firstFret - 1);
1276 : for (int i = 0; i < (gpHeader ? 7 : 6); ++i) {
1277 : int currentFret = readInt();
1278 : // read the frets and add them to the fretboard
1279 : // subtract 1 extra from numStrings as we count from 0
1280 : if (i > numStrings - 1) {
1281 : } else if (currentFret > 0) {
1282 : fret->setDot(numStrings - 1 - i, currentFret - firstFret + 1, true);
1283 : } else if (currentFret == 0) {
1284 : fret->setDot(numStrings - 1 - i, 0, true);
1285 : fret->setMarker(numStrings - 1 - i, FretMarkerType::CIRCLE);
1286 : } else if (currentFret == -1) {
1287 : fret->setDot(numStrings - 1 - i, 0, true);
1288 : fret->setMarker(numStrings - 1 - i, FretMarkerType::CROSS);
1289 : }
1290 : }
1291 : seg->add(fret);
1292 : if (!name.isEmpty()) {
1293 : Harmony* harmony = new Harmony(seg);
1294 : harmony->setHarmony(name);
1295 : harmony->setTrack(track);
1296 : fret->add(harmony);
1297 : }
1298 : }
1299 4 : } else if (!name.isEmpty()) {
1300 0 : Harmony* harmony = new Harmony(seg);
1301 0 : harmony->setHarmony(name);
1302 0 : harmony->setTrack(track);
1303 0 : seg->add(harmony);
1304 : }
1305 4 : }
1306 :
1307 : //---------------------------------------------------------
1308 : // restsForEmptyBeats
1309 : //---------------------------------------------------------
1310 :
1311 1083 : void GuitarPro::restsForEmptyBeats(Segment* seg, Measure* measure, ChordRest* cr, Fraction& l, int track, const Fraction& tick)
1312 : {
1313 : /* this can happen as Guitar Pro versions 5 and below allows
1314 : * users to create empty segments. Here, we create rests and
1315 : * make them invisible so users get the same visual if they are
1316 : * at a valid tick of the score. */
1317 1083 : if (seg->empty()) {
1318 27 : if (tick < measure->endTick()) {
1319 0 : cr = Factory::createRest(seg);
1320 0 : cr->setTrack(track);
1321 0 : TDuration d(l);
1322 0 : cr->setDurationType(d);
1323 0 : cr->setVisible(false);
1324 0 : seg->add(cr);
1325 : } else {
1326 27 : measure->remove(seg);
1327 : }
1328 : }
1329 1083 : }
1330 :
1331 : //---------------------------------------------------------
1332 : // createSlur
1333 : //---------------------------------------------------------
1334 :
1335 934 : void GuitarPro::createSlur(bool hasSlur, staff_idx_t staffIdx, ChordRest* cr)
1336 : {
1337 934 : if (hasSlur && (slurs[staffIdx] == 0)) {
1338 4 : Slur* slur = Factory::createSlur(score->dummy());
1339 4 : slur->setTrack(cr->track());
1340 4 : slur->setTrack2(cr->track());
1341 4 : slur->setTick(cr->tick());
1342 4 : slur->setTick2(cr->tick());
1343 4 : slur->setStartElement(cr);
1344 4 : slur->setEndElement(cr);
1345 4 : slurs[staffIdx] = slur;
1346 4 : score->addElement(slur);
1347 930 : } else if (slurs[staffIdx] && !hasSlur) {
1348 3 : Slur* s = slurs[staffIdx];
1349 3 : slurs[staffIdx] = 0;
1350 3 : s->setEndElement(cr);
1351 3 : s->setTick2(cr->tick());
1352 3 : s->setTrack2(cr->track());
1353 : }
1354 934 : }
1355 :
1356 : //---------------------------------------------------------
1357 : // read
1358 : //---------------------------------------------------------
1359 :
1360 0 : bool GuitarPro2::read(IODevice* io)
1361 : {
1362 0 : m_continiousElementsBuilder = std::make_unique<ContiniousElementsBuilder>(score);
1363 0 : m_guitarBendImporter = std::make_unique<GuitarBendImporter>(score);
1364 :
1365 0 : f = io;
1366 0 : curPos = 30;
1367 :
1368 0 : title = readDelphiString();
1369 0 : subtitle = readDelphiString();
1370 0 : artist = readDelphiString();
1371 0 : album = readDelphiString();
1372 0 : composer = readDelphiString();
1373 0 : String copyright = readDelphiString();
1374 0 : if (!copyright.isEmpty()) {
1375 0 : score->setMetaTag(u"copyright", copyright);
1376 : }
1377 :
1378 0 : readDelphiString(); // transcriber
1379 0 : readDelphiString(); // instructions
1380 0 : int n = readInt();
1381 0 : for (int i = 0; i < n; ++i) {
1382 0 : comments.append(readDelphiString());
1383 : }
1384 :
1385 0 : /*uint8_t num =*/ readUInt8(); // Shuffle rhythm feel
1386 :
1387 0 : int temp = readInt();
1388 :
1389 : // int octave = 0;
1390 0 : /*int key =*/ readInt(); // key
1391 :
1392 0 : for (int i = 0; i < GP_MAX_TRACK_NUMBER * 2; ++i) {
1393 0 : channelDefaults[i].patch = readInt();
1394 0 : channelDefaults[i].volume = readUInt8() * 8 - 1;
1395 0 : channelDefaults[i].pan = readUInt8() * 8 - 1;
1396 0 : channelDefaults[i].chorus = readUInt8() * 8 - 1;
1397 0 : channelDefaults[i].reverb = readUInt8() * 8 - 1;
1398 0 : channelDefaults[i].phase = readUInt8() * 8 - 1;
1399 0 : channelDefaults[i].tremolo = readUInt8() * 8 - 1;
1400 0 : readUInt8(); // padding
1401 0 : readUInt8();
1402 : }
1403 0 : measures = readInt();
1404 0 : staves = readInt();
1405 0 : initDynamics(staves);
1406 :
1407 0 : int tnumerator = 4;
1408 0 : int tdenominator = 4;
1409 0 : for (size_t i = 0; i < measures; ++i) {
1410 0 : GpBar bar;
1411 0 : uint8_t barBits = readUInt8();
1412 0 : if (barBits & SCORE_TIMESIG_NUMERATOR) {
1413 0 : tnumerator = readUInt8();
1414 : }
1415 0 : if (barBits & SCORE_TIMESIG_DENOMINATOR) {
1416 0 : tdenominator = readUInt8();
1417 : }
1418 0 : if (barBits & SCORE_REPEAT_START) {
1419 0 : bar.repeatFlags = bar.repeatFlags | mu::engraving::Repeat::START;
1420 : }
1421 0 : if (barBits & SCORE_REPEAT_END) {
1422 0 : bar.repeatFlags = bar.repeatFlags | mu::engraving::Repeat::END;
1423 0 : bar.repeats = readUInt8() + 1;
1424 : }
1425 0 : if (barBits & SCORE_VOLTA) {
1426 0 : uint8_t voltaNumber = readUInt8();
1427 0 : while (voltaNumber > 0) {
1428 : // volta information is represented as a binary number
1429 0 : bar.volta.voltaType = GP_VOLTA_BINARY;
1430 0 : bar.volta.voltaInfo.push_back(voltaNumber & 1);
1431 0 : voltaNumber >>= 1;
1432 : }
1433 : }
1434 0 : if (barBits & SCORE_MARKER) {
1435 0 : bar.marker = readDelphiString(); // new section?
1436 0 : /*int color =*/ readInt(); // color?
1437 : }
1438 0 : if (barBits & SCORE_KEYSIG) {
1439 0 : bar.keysig = readUInt8();
1440 0 : /*uint8_t c =*/ readUInt8(); // minor
1441 : }
1442 0 : if (barBits & SCORE_DOUBLE_BAR) {
1443 0 : bar.barLine = BarLineType::DOUBLE;
1444 : }
1445 0 : bar.timesig = Fraction(tnumerator, tdenominator);
1446 0 : bars.push_back(bar);
1447 0 : }
1448 :
1449 : //
1450 : // create a part for every staff
1451 : //
1452 0 : for (size_t staffIdx = 0; staffIdx < staves; ++staffIdx) {
1453 0 : Part* part = new Part(score);
1454 0 : Staff* s = Factory::createStaff(part);
1455 :
1456 0 : score->appendStaff(s);
1457 0 : score->appendPart(part);
1458 : }
1459 :
1460 0 : Fraction ts;
1461 0 : Fraction tick = { 0, 1 };
1462 0 : for (size_t i = 0; i < measures; ++i) {
1463 0 : Fraction nts = bars[i].timesig;
1464 0 : Measure* m = Factory::createMeasure(score);
1465 0 : m->setTick(tick);
1466 0 : m->setTimesig(nts);
1467 0 : m->setTicks(nts);
1468 :
1469 0 : if (i == 0 || ts != nts) {
1470 0 : for (size_t staffIdx = 0; staffIdx < staves; ++staffIdx) {
1471 0 : Segment* s = m->getSegment(SegmentType::TimeSig, tick);
1472 0 : TimeSig* t = Factory::createTimeSig(s);
1473 0 : t->setTrack(staffIdx * VOICES);
1474 0 : t->setSig(nts);
1475 0 : s->add(t);
1476 : }
1477 : }
1478 :
1479 0 : score->measures()->append(m);
1480 0 : tick += nts;
1481 0 : ts = nts;
1482 : }
1483 :
1484 0 : for (size_t i = 0; i < staves; ++i) {
1485 : int tuning[GP_MAX_STRING_NUMBER];
1486 :
1487 0 : uint8_t c = readUInt8(); // simulations bitmask
1488 0 : if (c & 0x2) { // 12 stringed guitar
1489 : }
1490 0 : if (c & 0x4) { // banjo track
1491 : }
1492 0 : String name = readPascalString(40);
1493 0 : int strings = readInt();
1494 0 : if (strings <= 0 || strings > GP_MAX_STRING_NUMBER) {
1495 0 : return false;
1496 : }
1497 0 : for (int j = 0; j < strings; ++j) {
1498 0 : tuning[j] = readInt();
1499 : }
1500 0 : for (int j = strings; j < GP_MAX_STRING_NUMBER; ++j) {
1501 0 : readInt();
1502 : }
1503 0 : /*int midiPort =*/ readInt(); // - 1;
1504 0 : int midiChannel = readInt() - 1;
1505 0 : if (midiChannel < 0 || midiChannel >= static_cast<int>(channelDefaults.size())) {
1506 0 : LOGE() << "midiChannel " << midiChannel << " out of range 0-" << channelDefaults.size();
1507 0 : return false;
1508 : }
1509 0 : /*int midiChannel2 =*/ readInt(); // - 1;
1510 0 : int frets = readInt();
1511 0 : int capo = readInt();
1512 0 : /*int color =*/ readInt();
1513 :
1514 0 : std::vector<int> tuning2(strings);
1515 : //int tuning2[strings];
1516 0 : for (int k = 0; k < strings; ++k) {
1517 0 : tuning2[strings - k - 1] = tuning[k];
1518 : }
1519 0 : bool useFlats = createTuningString(strings, &tuning2[0]);
1520 0 : StringData stringData(frets, strings, &tuning2[0], useFlats);
1521 0 : Part* part = score->staff(i)->part();
1522 0 : Instrument* instr = part->instrument();
1523 0 : instr->setStringData(stringData);
1524 0 : instr->setSingleNoteDynamics(false);
1525 0 : part->setPlainLongName(name);
1526 :
1527 : //
1528 : // determine clef
1529 : //
1530 0 : Staff* staff = score->staff(i);
1531 0 : int patch = channelDefaults[midiChannel].patch;
1532 0 : ClefType clefId = ClefType::G;
1533 0 : if (midiChannel == GP_DEFAULT_PERCUSSION_CHANNEL) {
1534 0 : clefId = ClefType::PERC;
1535 0 : StaffTypes type = StaffTypes::PERC_DEFAULT;
1536 0 : if (auto it = drumset::PERC_STAFF_LINES_FROM_INSTRUMENT.find(name.toStdString());
1537 0 : it != drumset::PERC_STAFF_LINES_FROM_INSTRUMENT.end()) {
1538 0 : drumset::initGuitarProPercussionSet(it->second);
1539 0 : drumset::setInstrumentDrumset(instr, it->second);
1540 0 : switch (it->second.numLines) {
1541 0 : case 1:
1542 0 : type = StaffTypes::PERC_1LINE;
1543 0 : break;
1544 0 : case 2:
1545 0 : type = StaffTypes::PERC_2LINE;
1546 0 : break;
1547 0 : case 3:
1548 0 : type = StaffTypes::PERC_3LINE;
1549 0 : break;
1550 0 : default:
1551 0 : type = StaffTypes::PERC_DEFAULT;
1552 0 : break;
1553 : }
1554 : } else {
1555 0 : drumset::initGuitarProDrumset();
1556 0 : instr->setDrumset(drumset::gpDrumset);
1557 : }
1558 0 : staff->setStaffType(Fraction(0, 1), *StaffType::preset(type));
1559 : } else {
1560 0 : clefId = defaultClef(patch);
1561 : }
1562 0 : Measure* measure = score->firstMeasure();
1563 0 : Segment* segment = measure->getSegment(SegmentType::HeaderClef, Fraction(0, 1));
1564 0 : Clef* clef = Factory::createClef(segment);
1565 0 : clef->setClefType(clefId);
1566 0 : clef->setTrack(i * VOICES);
1567 0 : segment->add(clef);
1568 :
1569 0 : if (capo > 0 && !engravingConfiguration()->guitarProImportExperimental()) {
1570 0 : Segment* s = measure->getSegment(SegmentType::ChordRest, measure->tick());
1571 0 : const size_t track = i * VOICES;
1572 :
1573 0 : CapoParams params;
1574 0 : params.active = true;
1575 0 : params.transposeMode = CapoParams::TransposeMode::TAB_ONLY;
1576 0 : params.fretPosition = capo;
1577 :
1578 0 : Capo* capoEl = Factory::createCapo(s);
1579 0 : capoEl->setTrack(track);
1580 0 : capoEl->setParams(params);
1581 0 : s->add(capoEl);
1582 :
1583 0 : staff->insertCapoParams({ 0, 1 }, params, true);
1584 0 : }
1585 :
1586 0 : InstrChannel* ch = instr->channel(0);
1587 0 : if (midiChannel == int(StaffTypes::PERC_DEFAULT)) {
1588 0 : ch->setProgram(0);
1589 0 : ch->setBank(128);
1590 : } else {
1591 0 : ch->setProgram(patch);
1592 0 : ch->setBank(0);
1593 : }
1594 0 : ch->setVolume(channelDefaults[midiChannel].volume);
1595 0 : ch->setPan(channelDefaults[midiChannel].pan);
1596 0 : ch->setChorus(channelDefaults[midiChannel].chorus);
1597 0 : ch->setReverb(channelDefaults[midiChannel].reverb);
1598 : // missing: phase, tremolo
1599 0 : }
1600 :
1601 0 : previousTempo = temp;
1602 0 : Measure* measure = score->firstMeasure();
1603 0 : bool mixChange = false;
1604 0 : for (size_t bar = 0; bar < measures; ++bar, measure = measure->nextMeasure()) {
1605 0 : const GpBar& gpbar = bars[bar];
1606 :
1607 0 : if (!gpbar.marker.isEmpty()) {
1608 0 : Segment* segment = measure->getSegment(SegmentType::ChordRest, measure->tick());
1609 0 : RehearsalMark* s = new RehearsalMark(segment);
1610 0 : s->setPlainText(gpbar.marker.trimmed());
1611 0 : s->setTrack(0);
1612 0 : segment->add(s);
1613 : }
1614 :
1615 0 : std::vector<Tuplet*> tuplets(staves);
1616 : // Tuplet* tuplets[staves];
1617 0 : for (size_t staffIdx = 0; staffIdx < staves; ++staffIdx) {
1618 0 : tuplets[staffIdx] = 0;
1619 : }
1620 :
1621 0 : for (size_t staffIdx = 0; staffIdx < staves; ++staffIdx) {
1622 0 : Fraction measureLen = { 0, 1 };
1623 0 : track_idx_t track = staffIdx * VOICES;
1624 0 : Fraction fraction = measure->tick();
1625 0 : int beats = readInt();
1626 0 : for (int beat = 0; beat < beats; ++beat) {
1627 : // int pause = 0;
1628 0 : uint8_t beatBits = readUInt8();
1629 0 : bool dotted = beatBits & BEAT_DOTTED;
1630 0 : if (beatBits & BEAT_PAUSE) {
1631 : /*pause =*/
1632 0 : readUInt8();
1633 : }
1634 0 : int len = readChar();
1635 0 : int tuple = 0;
1636 0 : if (beatBits & BEAT_TUPLET) {
1637 0 : tuple = readInt();
1638 : }
1639 0 : Segment* segment = measure->getSegment(SegmentType::ChordRest, fraction);
1640 0 : if (beatBits & BEAT_CHORD) {
1641 0 : int numStrings = static_cast<int>(score->staff(staffIdx)->part()->instrument()->stringData()->strings());
1642 0 : int header = readUInt8();
1643 0 : String name;
1644 0 : if ((header & 1) == 0) {
1645 0 : name = readDelphiString();
1646 0 : readChord(segment, static_cast<int>(track), numStrings, name, false);
1647 : } else {
1648 0 : skip(25);
1649 0 : name = readPascalString(34);
1650 0 : readChord(segment, static_cast<int>(track), numStrings, name, true);
1651 0 : skip(36);
1652 : }
1653 0 : }
1654 0 : Lyrics* lyrics = 0;
1655 0 : if (beatBits & BEAT_LYRICS) {
1656 0 : String txt = readDelphiString();
1657 0 : lyrics = Factory::createLyrics(score->dummy());
1658 0 : lyrics->setPlainText(txt);
1659 0 : }
1660 0 : if (beatBits & BEAT_EFFECTS) {
1661 0 : readBeatEffects(static_cast<int>(track), segment);
1662 : }
1663 :
1664 0 : if (beatBits & BEAT_MIX_CHANGE) {
1665 0 : readMixChange(measure);
1666 0 : mixChange = true;
1667 : }
1668 :
1669 0 : int strings = readUInt8(); // used strings mask
1670 :
1671 0 : Fraction l = len2fraction(len);
1672 : ChordRest* cr;
1673 0 : if (strings) {
1674 0 : cr = Factory::createChord(segment);
1675 : } else {
1676 0 : cr = Factory::createRest(segment);
1677 : }
1678 0 : cr->setTrack(track);
1679 0 : if (lyrics) {
1680 0 : cr->add(lyrics);
1681 : }
1682 :
1683 0 : TDuration d(l);
1684 0 : d.setDots(dotted ? 1 : 0);
1685 :
1686 0 : if (dotted) {
1687 0 : l = l + (l * Fraction(1, 2));
1688 : }
1689 :
1690 0 : if (tuple) {
1691 0 : Tuplet* tuplet = tuplets[staffIdx];
1692 0 : if ((tuplet == 0) || (tuplet->elementsDuration() == tuplet->baseLen().fraction() * tuplet->ratio().numerator())) {
1693 0 : tuplet = Factory::createTuplet(measure);
1694 0 : tuplet->setTick(fraction);
1695 0 : tuplet->setTrack(cr->track());
1696 0 : tuplets[staffIdx] = tuplet;
1697 0 : setTuplet(tuplet, tuple);
1698 : }
1699 0 : tuplet->setTrack(track);
1700 0 : tuplet->setBaseLen(l);
1701 0 : tuplet->setTicks(l * tuplet->ratio().denominator());
1702 0 : cr->setTuplet(tuplet);
1703 0 : tuplet->add(cr);
1704 : }
1705 :
1706 0 : cr->setTicks(l);
1707 0 : cr->setDurationType(d);
1708 0 : segment->add(cr);
1709 0 : Staff* staff = cr->staff();
1710 0 : int numStrings = static_cast<int>(staff->part()->instrument()->stringData()->strings());
1711 0 : ReadNoteResult readResult;
1712 0 : bool hasLetRing = false;
1713 0 : bool hasPalmMute = false;
1714 0 : for (int i = 6; i >= 0; --i) {
1715 0 : if (strings & (1 << i) && ((6 - i) < numStrings)) {
1716 0 : Note* note = Factory::createNote(toChord(cr));
1717 0 : toChord(cr)->add(note);
1718 0 : readResult = readNote(6 - i, note);
1719 0 : hasLetRing = readResult.letRing || hasLetRing;
1720 0 : hasPalmMute = readResult.palmMute || hasPalmMute;
1721 0 : note->setTpcFromPitch();
1722 : }
1723 : }
1724 0 : restsForEmptyBeats(segment, measure, cr, l, static_cast<int>(track), fraction);
1725 0 : fraction += cr->actualTicks();
1726 0 : measureLen += cr->actualTicks();
1727 0 : addLetRing(cr, hasLetRing);
1728 0 : addPalmMute(cr, hasPalmMute);
1729 : }
1730 0 : if (measureLen < measure->ticks()) {
1731 0 : score->setRest(fraction, track, measure->ticks() - measureLen, false, nullptr, false);
1732 0 : m_continiousElementsBuilder->notifyUncompletedMeasure();
1733 : }
1734 : }
1735 0 : if (bar == 1 && !mixChange) {
1736 0 : setTempo(temp, score->firstMeasure());
1737 : }
1738 0 : }
1739 :
1740 0 : m_continiousElementsBuilder->addElementsToScore();
1741 0 : addTunings();
1742 0 : return true;
1743 0 : }
1744 :
1745 : //---------------------------------------------------------
1746 : // readNote
1747 : //---------------------------------------------------------
1748 :
1749 87 : GuitarPro::ReadNoteResult GuitarPro1::readNote(int string, Note* note)
1750 : {
1751 87 : ReadNoteResult readResult;
1752 87 : uint8_t noteBits = readUInt8();
1753 87 : if (noteBits & NOTE_GHOST) {
1754 0 : if (version == 300) {
1755 0 : note->setGhost(true);
1756 : } else {
1757 0 : note->setHeadGroup(NoteHeadGroup::HEAD_CROSS);
1758 0 : note->setGhost(true);
1759 : }
1760 : }
1761 :
1762 87 : bool tieNote = false;
1763 87 : uint8_t variant = 1;
1764 87 : if (noteBits & NOTE_DEAD) {
1765 87 : variant = readUInt8();
1766 87 : if (variant == 1) { // normal note
1767 5 : } else if (variant == 2) {
1768 2 : tieNote = true;
1769 3 : } else if (variant == 3) { // dead notes
1770 3 : note->setHeadGroup(NoteHeadGroup::HEAD_CROSS);
1771 3 : note->setDeadNote(true);
1772 : } else {
1773 0 : LOGD("unknown note variant: %d", variant);
1774 : }
1775 : }
1776 :
1777 : //
1778 : // noteBits:
1779 : // 7 - Right hand or left hand fingering;
1780 : // 6 - Accentuated note
1781 : // 5 - Note type (rest, empty note, normal note);
1782 : // 4 - note dynamic;
1783 : // 3 - Presence of effects linked to the note;
1784 : // 2 - Ghost note;
1785 : // 1 - Dotted note; ?
1786 : // 0 - Time-independent duration
1787 :
1788 87 : if (noteBits & 0x1) { // note != beat
1789 0 : int a = readUInt8(); // length
1790 0 : int b = readUInt8(); // t
1791 0 : LOGD("Time independent note len, len %d t %d", a, b);
1792 : }
1793 87 : if (noteBits & 0x2) { // note is dotted
1794 : //readUInt8();
1795 : }
1796 :
1797 87 : int& previousDynamic = previousDynamicByTrack[note->track()];
1798 :
1799 : // set dynamic information on note if different from previous note
1800 87 : if (noteBits & NOTE_DYNAMIC) {
1801 17 : int d = readChar();
1802 17 : if (previousDynamic != d) {
1803 4 : previousDynamic = d;
1804 4 : addDynamic(note, d);
1805 : }
1806 70 : } else if (previousDynamic != DEFAULT_DYNAMIC) {
1807 4 : previousDynamic = DEFAULT_DYNAMIC;
1808 4 : addDynamic(note, previousDynamic);
1809 : }
1810 :
1811 87 : int fretNumber = -1;
1812 87 : if (noteBits & NOTE_FRET) {
1813 87 : fretNumber = readUInt8();
1814 : }
1815 :
1816 87 : if (noteBits & NOTE_FINGERING) { // fingering
1817 0 : int a = readUInt8();
1818 0 : int b = readUInt8();
1819 0 : LOGD("Fingering=========%d %d", a, b);
1820 : }
1821 87 : if (noteBits & BEAT_EFFECTS) {
1822 6 : uint8_t modMask1 = readUInt8();
1823 6 : uint8_t modMask2 = 0;
1824 6 : if (version >= 400) {
1825 0 : modMask2 = readUInt8();
1826 : }
1827 6 : if (modMask1 & EFFECT_BEND) {
1828 5 : readBend(note);
1829 : }
1830 6 : if (modMask1 & EFFECT_GRACE) {
1831 : // GP3 grace note
1832 0 : int fret = readUInt8(); // grace fret
1833 0 : int dynamic = readUInt8(); // grace dynamic
1834 0 : int transition = readUInt8(); // grace transition
1835 0 : int duration = readUInt8(); // grace duration
1836 :
1837 0 : int grace_len = Constants::DIVISION / 8;
1838 0 : if (duration == 1) {
1839 0 : grace_len = Constants::DIVISION / 8; //32nd
1840 0 : } else if (duration == 2) {
1841 0 : grace_len = Constants::DIVISION / 6; //24th
1842 0 : } else if (duration == 3) {
1843 0 : grace_len = Constants::DIVISION / 4; //16th
1844 : }
1845 0 : Note* gn = Factory::createNote(score->dummy());
1846 :
1847 0 : if (fret == 255) {
1848 0 : gn->setHeadGroup(NoteHeadGroup::HEAD_CROSS);
1849 0 : gn->setGhost(true);
1850 : }
1851 0 : if (fret == 255) {
1852 0 : fret = 0;
1853 : }
1854 0 : gn->setFret(fret);
1855 0 : gn->setString(string);
1856 0 : int grace_pitch = note->staff()->part()->instrument()->stringData()->getPitch(string, fret, note->staff(), note->tick());
1857 0 : gn->setPitch(grace_pitch);
1858 0 : gn->setTpcFromPitch();
1859 :
1860 0 : Chord* gc = nullptr;
1861 0 : if (note->chord()->graceNotes().size()) {
1862 0 : gc = note->chord()->graceNotes().front();
1863 : }
1864 0 : if (!gc) {
1865 0 : gc = Factory::createChord(score->dummy());
1866 0 : TDuration d;
1867 0 : d.setVal(grace_len);
1868 0 : if (grace_len == Constants::DIVISION / 6) {
1869 0 : d.setDots(1);
1870 : }
1871 0 : gc->setDurationType(d);
1872 0 : gc->setTicks(d.fraction());
1873 0 : gc->setNoteType(NoteType::ACCIACCATURA);
1874 0 : gc->mutldata()->setMag(note->chord()->staff()->staffMag(Fraction(0, 1)) * score->style().styleD(Sid::graceNoteMag));
1875 0 : note->chord()->add(gc); // sets parent + track
1876 0 : addDynamic(gn, dynamic);
1877 : }
1878 :
1879 0 : gc->add(gn);
1880 :
1881 0 : if (transition == 0) {
1882 : // no transition
1883 0 : } else if (transition == 1) {
1884 : //note->setSlideNote(gn);
1885 0 : Glissando* glis = new Glissando(gn);
1886 0 : glis->setGlissandoType(GlissandoType::STRAIGHT);
1887 0 : gn->chord()->add(glis);
1888 0 : glis->setStartElement(gn);
1889 0 : glis->setTick(gn->chord()->tick());
1890 0 : glis->setTrack(gn->track());
1891 0 : glis->setEndElement(note);
1892 0 : glis->setTick2(note->chord()->tick());
1893 0 : glis->setTrack2(note->track());
1894 0 : score->addElement(glis);
1895 : //HammerOn here??? Maybe version...
1896 :
1897 0 : Slur* slur1 = Factory::createSlur(score->dummy());
1898 0 : slur1->setStartElement(gc);
1899 0 : slur1->setEndElement(note->chord());
1900 0 : slur1->setTick(gc->tick());
1901 0 : slur1->setTick2(note->chord()->tick());
1902 0 : slur1->setTrack(gc->track());
1903 0 : slur1->setTrack2(note->track());
1904 0 : score->addElement(slur1);
1905 :
1906 : //TODO: Add a 'slide' guitar effect when implemented
1907 0 : } else if (transition == 2 && fretNumber >= 0 && fretNumber <= 255 && fretNumber != gn->fret()) {
1908 : /*QList<PitchValue> points;
1909 : points.append(PitchValue(0,0, false));
1910 : points.append(PitchValue(60,(fretNumber-gn->fret())*100, false));
1911 :
1912 : Bend* b = Factory::createBend(note->score());
1913 : b->setPoints(points);
1914 : b->setTrack(gn->track());
1915 : gn->add(b);*/
1916 0 : } else if (transition == 3) {
1917 : // TODO:
1918 : // major: replace with a 'hammer-on' guitar effect when implemented
1919 : // minor: make slurs for parts
1920 :
1921 0 : ChordRest* cr1 = toChord(gc);
1922 0 : ChordRest* cr2 = toChord(note->chord());
1923 :
1924 0 : Slur* slur1 = Factory::createSlur(score->dummy());
1925 0 : slur1->setStartElement(cr1);
1926 0 : slur1->setEndElement(cr2);
1927 0 : slur1->setTick(cr1->tick());
1928 0 : slur1->setTick2(cr2->tick());
1929 0 : slur1->setTrack(cr1->track());
1930 0 : slur1->setTrack2(cr2->track());
1931 0 : score->addElement(slur1);
1932 : }
1933 : }
1934 6 : if (modMask1 & EFFECT_HAMMER) { // hammer on / pull off
1935 0 : readResult.slur = true;
1936 : }
1937 6 : if (modMask1 & EFFECT_LET_RING) { // let ring
1938 0 : readResult.letRing = true;
1939 : }
1940 6 : if (modMask1 & EFFECT_SLIDE_OLD) {
1941 1 : slideList.push_back(note);
1942 : }
1943 :
1944 6 : if (version >= 400) {
1945 0 : if (modMask2 & EFFECT_STACCATO) {
1946 : }
1947 0 : if (modMask2 & EFFECT_PALM_MUTE) {
1948 0 : readResult.palmMute = true;
1949 : }
1950 0 : if (modMask2 & EFFECT_TREMOLO) {
1951 0 : readUInt8();
1952 : }
1953 0 : if (modMask2 & EFFECT_ARTIFICIAL_HARMONIC) {
1954 : /*int type =*/
1955 0 : readUInt8();
1956 : //TODO-ws if (type == 1 || type == 4 || type == 5)
1957 : // note->setHarmonic(true);
1958 : }
1959 0 : if (modMask2 & EFFECT_TRILL) {
1960 : //TODO-ws note->setTrillFret(readUInt8()); // trill fret
1961 0 : readUInt8(); // trill length
1962 : }
1963 : }
1964 : }
1965 87 : if (fretNumber == -1) {
1966 0 : LOGD("Note: no fret number, tie %d", tieNote);
1967 : }
1968 87 : Staff* staff = note->staff();
1969 87 : if (fretNumber == 255) {
1970 0 : fretNumber = 0;
1971 0 : note->setHeadGroup(NoteHeadGroup::HEAD_CROSS);
1972 0 : note->setGhost(true);
1973 : }
1974 : // dead note represented as high numbers - fix to zero
1975 87 : if (fretNumber > 99 || fretNumber == -1) {
1976 0 : fretNumber = 0;
1977 : }
1978 87 : int pitch = staff->part()->instrument()->stringData()->getPitch(string, fretNumber, staff, note->tick());
1979 :
1980 : /* it's possible to specify extraordinarily high pitches by
1981 : specifying fret numbers that don't exist. This is an issue that
1982 : comes from tuxguitar. Just set to maximum pitch. GP6 actually
1983 : sets the fret number to 0 also, so that's what I've opted to do
1984 : here. */
1985 87 : if (pitch > MAX_PITCH) {
1986 0 : fretNumber = 0;
1987 0 : pitch = MAX_PITCH;
1988 : }
1989 :
1990 87 : note->setFret(fretNumber);
1991 87 : note->setString(string);
1992 87 : note->setPitch(pitch);
1993 :
1994 87 : if (tieNote) {
1995 2 : bool found = false;
1996 2 : Chord* chord = note->chord();
1997 2 : Segment* segment = chord->segment()->prev1(SegmentType::ChordRest);
1998 2 : track_idx_t track = note->track();
1999 2 : std::vector<Chord*> chords;
2000 2 : Note* true_note = nullptr;
2001 2 : while (segment) {
2002 2 : EngravingItem* e = segment->element(track);
2003 2 : if (e) {
2004 2 : if (e->isChord()) {
2005 2 : Chord* chord2 = toChord(e);
2006 2 : for (Note* note2 : chord2->notes()) {
2007 2 : if (note2->string() == string) {
2008 2 : if (chords.empty()) {
2009 2 : Tie* tie = Factory::createTie(note2);
2010 2 : tie->setEndNote(note);
2011 2 : note2->add(tie);
2012 : }
2013 2 : note->setFret(note2->fret());
2014 2 : note->setPitch(note2->pitch());
2015 2 : found = true;
2016 2 : true_note = note2;
2017 2 : break;
2018 : }
2019 : }
2020 2 : if (!found) {
2021 0 : chords.push_back(chord2);
2022 : }
2023 : }
2024 2 : if (found) {
2025 2 : break;
2026 : }
2027 : }
2028 0 : segment = segment->prev1(SegmentType::ChordRest);
2029 : }
2030 :
2031 2 : if (chords.size() && true_note) {
2032 0 : Note* end_note = note;
2033 0 : for (unsigned int i = 0; i < chords.size(); ++i) {
2034 0 : Note* note2 = Factory::createNote(chords[i]);
2035 0 : note2->setString(true_note->string());
2036 0 : note2->setFret(true_note->fret());
2037 0 : note2->setPitch(true_note->pitch());
2038 0 : note2->setTpcFromPitch();
2039 0 : chords[i]->add(note2);
2040 0 : Tie* tie = Factory::createTie(note2);
2041 0 : tie->setEndNote(end_note);
2042 0 : end_note = note2;
2043 0 : note2->add(tie);
2044 : }
2045 0 : Tie* tie = Factory::createTie(true_note);
2046 0 : tie->setEndNote(end_note);
2047 0 : true_note->add(tie);
2048 : }
2049 2 : }
2050 :
2051 87 : return readResult;
2052 : }
2053 :
2054 : //---------------------------------------------------------
2055 : // readBeatEffects
2056 : //---------------------------------------------------------
2057 :
2058 0 : int GuitarPro1::readBeatEffects(int, Segment*)
2059 : {
2060 0 : uint8_t fxBits1 = readUInt8();
2061 0 : if (fxBits1 & BEAT_EFFECT) {
2062 0 : uint8_t num = readUInt8();
2063 0 : switch (num) {
2064 0 : case 0: // tremolo bar
2065 0 : readInt();
2066 0 : break;
2067 0 : default:
2068 0 : readInt();
2069 0 : break;
2070 : }
2071 : }
2072 0 : if (fxBits1 & BEAT_ARPEGGIO) {
2073 0 : readUInt8(); // down stroke length
2074 0 : readUInt8(); // up stroke length
2075 : }
2076 0 : return 0;
2077 : }
2078 :
2079 : //---------------------------------------------------------
2080 : // read
2081 : //---------------------------------------------------------
2082 :
2083 7 : bool GuitarPro3::read(IODevice* io)
2084 : {
2085 7 : m_continiousElementsBuilder = std::make_unique<ContiniousElementsBuilder>(score);
2086 7 : m_guitarBendImporter = std::make_unique<GuitarBendImporter>(score);
2087 :
2088 7 : f = io;
2089 7 : curPos = 30;
2090 :
2091 7 : title = readDelphiString();
2092 7 : subtitle = readDelphiString();
2093 7 : artist = readDelphiString();
2094 7 : album = readDelphiString();
2095 7 : composer = readDelphiString();
2096 7 : String copyright = readDelphiString();
2097 :
2098 7 : if (!copyright.isEmpty()) {
2099 2 : score->setMetaTag(u"copyright", copyright);
2100 : }
2101 :
2102 7 : readDelphiString(); // transcriber
2103 7 : readDelphiString(); // instructions
2104 11 : for (int i = 0, n = readInt(); i < n; ++i) {
2105 4 : comments.append(readDelphiString());
2106 : }
2107 :
2108 7 : /*uint8_t num =*/ readUInt8(); // Shuffle rhythm feel
2109 :
2110 7 : int temp = readInt();
2111 :
2112 : // int octave = 0;
2113 7 : key = readInt(); // key
2114 :
2115 455 : for (int i = 0; i < GP_MAX_TRACK_NUMBER * 2; ++i) {
2116 448 : channelDefaults[i].patch = readInt();
2117 448 : channelDefaults[i].volume = readUInt8() * 8 - 1;
2118 448 : channelDefaults[i].pan = readUInt8() * 8 - 1;
2119 448 : channelDefaults[i].chorus = readUInt8() * 8 - 1;
2120 448 : channelDefaults[i].reverb = readUInt8() * 8 - 1;
2121 448 : channelDefaults[i].phase = readUInt8() * 8 - 1;
2122 448 : channelDefaults[i].tremolo = readUInt8() * 8 - 1;
2123 448 : readUInt8(); // padding
2124 448 : readUInt8();
2125 : }
2126 7 : measures = readInt();
2127 7 : staves = readInt();
2128 7 : initDynamics(staves);
2129 :
2130 7 : slurs.resize(staves, nullptr);
2131 :
2132 7 : int tnumerator = 4;
2133 7 : int tdenominator = 4;
2134 30 : for (size_t i = 0; i < measures; ++i) {
2135 23 : GpBar bar;
2136 23 : uint8_t barBits = readUInt8();
2137 23 : if (barBits & SCORE_TIMESIG_NUMERATOR) {
2138 7 : tnumerator = readUInt8();
2139 : }
2140 23 : if (barBits & SCORE_TIMESIG_DENOMINATOR) {
2141 7 : tdenominator = readUInt8();
2142 : }
2143 23 : if (barBits & SCORE_REPEAT_START) {
2144 1 : bar.repeatFlags = bar.repeatFlags | mu::engraving::Repeat::START;
2145 : }
2146 23 : if (barBits & SCORE_REPEAT_END) { // number of repeats
2147 2 : bar.repeatFlags = bar.repeatFlags | mu::engraving::Repeat::END;
2148 2 : bar.repeats = readUInt8() + 1;
2149 : }
2150 23 : if (barBits & SCORE_VOLTA) { // a volta
2151 7 : uint8_t voltaNumber = readUInt8();
2152 : // voltas are represented as a binary number
2153 7 : bar.volta.voltaType = GP_VOLTA_BINARY;
2154 25 : while (voltaNumber > 0) {
2155 18 : bar.volta.voltaInfo.push_back(voltaNumber & 1);
2156 18 : voltaNumber >>= 1;
2157 : }
2158 : }
2159 23 : if (barBits & SCORE_MARKER) {
2160 0 : bar.marker = readDelphiString(); // new section?
2161 0 : /*int color =*/ readInt(); // color?
2162 : }
2163 23 : if (barBits & SCORE_KEYSIG) {
2164 0 : int currentKey = readUInt8();
2165 : /* key signatures are specified as
2166 : * 1# = 1, 2# = 2, ..., 7# = 7
2167 : * 1b = 255, 2b = 254, ... 7b = 249 */
2168 0 : bar.keysig = currentKey <= 7 ? currentKey : -256 + currentKey;
2169 0 : readUInt8(); // specifies major/minor mode
2170 : }
2171 :
2172 23 : if (barBits & SCORE_DOUBLE_BAR) {
2173 0 : bar.barLine = BarLineType::DOUBLE;
2174 : }
2175 23 : bar.timesig = Fraction(tnumerator, tdenominator);
2176 23 : bars.push_back(bar);
2177 23 : }
2178 :
2179 : //
2180 : // create a part for every staff
2181 : //
2182 14 : for (size_t staffIdx = 0; staffIdx < staves; ++staffIdx) {
2183 7 : Part* part = new Part(score);
2184 7 : Staff* s = Factory::createStaff(part);
2185 :
2186 7 : score->appendStaff(s);
2187 7 : score->appendPart(part);
2188 : }
2189 :
2190 7 : Fraction ts;
2191 7 : Fraction tick = { 0, 1 };
2192 30 : for (size_t i = 0; i < measures; ++i) {
2193 23 : Fraction nts = bars[i].timesig;
2194 23 : Measure* m = Factory::createMeasure(score);
2195 23 : m->setTick(tick);
2196 23 : m->setTimesig(nts);
2197 23 : m->setTicks(nts);
2198 :
2199 23 : if (i == 0 || ts != nts) {
2200 14 : for (size_t staffIdx = 0; staffIdx < staves; ++staffIdx) {
2201 7 : Segment* s = m->getSegment(SegmentType::TimeSig, tick);
2202 7 : TimeSig* t = Factory::createTimeSig(s);
2203 7 : t->setTrack(staffIdx * VOICES);
2204 7 : t->setSig(nts);
2205 7 : s->add(t);
2206 : }
2207 : }
2208 23 : if (i == 0 && key) {
2209 0 : for (size_t staffIdx = 0; staffIdx < staves; ++staffIdx) {
2210 0 : Segment* s = m->getSegment(SegmentType::KeySig, tick);
2211 0 : KeySig* t = Factory::createKeySig(s);
2212 0 : t->setKey(Key(key));
2213 0 : t->setTrack(staffIdx * VOICES);
2214 0 : s->add(t);
2215 : }
2216 : }
2217 :
2218 23 : readVolta(&bars[i].volta, m);
2219 23 : m->setRepeatEnd(bars[i].repeatFlags == mu::engraving::Repeat::END);
2220 23 : m->setRepeatStart(bars[i].repeatFlags == mu::engraving::Repeat::START);
2221 23 : m->setRepeatJump(bars[i].repeatFlags == mu::engraving::Repeat::JUMP);
2222 : // m->setRepeatFlags(bars[i].repeatFlags);
2223 23 : m->setRepeatCount(bars[i].repeats);
2224 :
2225 : // reset the volta sequence if we have an opening repeat
2226 23 : if (bars[i].repeatFlags == mu::engraving::Repeat::START) {
2227 1 : voltaSequence = 1;
2228 : }
2229 : // otherwise, if we see an end repeat symbol, only reset if the bar after it does not contain a volta
2230 22 : else if (bars[i].repeatFlags == mu::engraving::Repeat::END && i < bars.size() - 1) {
2231 2 : if (bars[i + 1].volta.voltaInfo.size() == 0) {
2232 1 : voltaSequence = 1;
2233 : }
2234 : }
2235 :
2236 23 : score->measures()->append(m);
2237 23 : tick += nts;
2238 23 : ts = nts;
2239 : }
2240 :
2241 14 : for (size_t i = 0; i < staves; ++i) {
2242 : int tuning[GP_MAX_STRING_NUMBER];
2243 :
2244 7 : uint8_t c = readUInt8(); // simulations bitmask
2245 7 : if (c & 0x2) { // 12 stringed guitar
2246 : }
2247 7 : if (c & 0x4) { // banjo track
2248 : }
2249 7 : String name = readPascalString(40);
2250 7 : int strings = readInt();
2251 7 : if (strings <= 0 || strings > GP_MAX_STRING_NUMBER) {
2252 0 : return false;
2253 : }
2254 47 : for (int j = 0; j < strings; ++j) {
2255 40 : tuning[j] = readInt();
2256 : }
2257 16 : for (int j = strings; j < GP_MAX_STRING_NUMBER; ++j) {
2258 9 : readInt();
2259 : }
2260 7 : int midiPort = readInt() - 1;
2261 7 : int midiChannel = readInt() - 1;
2262 14 : if (midiChannel < 0 || midiChannel >= static_cast<int>(channelDefaults.size())) {
2263 0 : LOGE() << "midiChannel " << midiChannel << " out of range 0-" << channelDefaults.size();
2264 0 : return false;
2265 : }
2266 7 : /*int midiChannel2 =*/ readInt(); // - 1;
2267 7 : int frets = readInt();
2268 7 : int capo = readInt();
2269 7 : /*int color =*/ readInt();
2270 :
2271 7 : std::vector<int> tuning2(strings);
2272 : //int tuning2[strings];
2273 47 : for (int k = 0; k < strings; ++k) {
2274 40 : tuning2[strings - k - 1] = tuning[k];
2275 : }
2276 7 : bool useFlats = createTuningString(strings, &tuning2[0]);
2277 7 : StringData stringData(frets, strings, &tuning2[0], useFlats);
2278 7 : Part* part = score->staff(i)->part();
2279 7 : Instrument* instr = part->instrument();
2280 7 : instr->setStringData(stringData);
2281 7 : instr->setSingleNoteDynamics(false);
2282 7 : part->setPlainLongName(name);
2283 : //
2284 : // determine clef
2285 : //
2286 7 : Staff* staff = score->staff(i);
2287 7 : int patch = channelDefaults[midiChannel].patch;
2288 7 : ClefType clefId = ClefType::G;
2289 7 : if (midiChannel == GP_DEFAULT_PERCUSSION_CHANNEL) {
2290 0 : clefId = ClefType::PERC;
2291 0 : StaffTypes type = StaffTypes::PERC_DEFAULT;
2292 0 : if (auto it = drumset::PERC_STAFF_LINES_FROM_INSTRUMENT.find(name.toStdString());
2293 0 : it != drumset::PERC_STAFF_LINES_FROM_INSTRUMENT.end()) {
2294 0 : drumset::initGuitarProPercussionSet(it->second);
2295 0 : drumset::setInstrumentDrumset(instr, it->second);
2296 0 : switch (it->second.numLines) {
2297 0 : case 1:
2298 0 : type = StaffTypes::PERC_1LINE;
2299 0 : break;
2300 0 : case 2:
2301 0 : type = StaffTypes::PERC_2LINE;
2302 0 : break;
2303 0 : case 3:
2304 0 : type = StaffTypes::PERC_3LINE;
2305 0 : break;
2306 0 : default:
2307 0 : type = StaffTypes::PERC_DEFAULT;
2308 0 : break;
2309 : }
2310 : } else {
2311 0 : drumset::initGuitarProDrumset();
2312 0 : instr->setDrumset(drumset::gpDrumset);
2313 : }
2314 0 : staff->setStaffType(Fraction(0, 1), *StaffType::preset(type));
2315 : } else {
2316 7 : clefId = defaultClef(patch);
2317 : }
2318 7 : Measure* measure = score->firstMeasure();
2319 7 : Segment* segment = measure->getSegment(SegmentType::HeaderClef, Fraction(0, 1));
2320 7 : Clef* clef = Factory::createClef(segment);
2321 7 : clef->setClefType(clefId);
2322 7 : clef->setTrack(i * VOICES);
2323 7 : segment->add(clef);
2324 :
2325 7 : if (capo > 0) {
2326 1 : Segment* s = measure->getSegment(SegmentType::ChordRest, measure->tick());
2327 1 : const size_t track = i * VOICES;
2328 :
2329 1 : CapoParams params;
2330 1 : params.active = true;
2331 1 : params.transposeMode = CapoParams::TransposeMode::TAB_ONLY;
2332 1 : params.fretPosition = capo;
2333 :
2334 1 : Capo* capoEl = Factory::createCapo(s);
2335 1 : capoEl->setTrack(track);
2336 1 : capoEl->setParams(params);
2337 1 : s->add(capoEl);
2338 :
2339 1 : staff->insertCapoParams({ 0, 1 }, params, true);
2340 1 : }
2341 :
2342 7 : InstrChannel* ch = instr->channel(0);
2343 7 : if (midiChannel == GP_DEFAULT_PERCUSSION_CHANNEL) {
2344 0 : ch->setProgram(0);
2345 0 : ch->setBank(128);
2346 : } else {
2347 7 : ch->setProgram(patch);
2348 7 : ch->setBank(0);
2349 : }
2350 7 : ch->setVolume(channelDefaults[midiChannel].volume);
2351 7 : ch->setPan(channelDefaults[midiChannel].pan);
2352 7 : ch->setChorus(channelDefaults[midiChannel].chorus);
2353 7 : ch->setReverb(channelDefaults[midiChannel].reverb);
2354 7 : staff->part()->setMidiChannel(midiChannel, midiPort);
2355 : // missing: phase, tremolo
2356 7 : }
2357 :
2358 7 : previousTempo = temp;
2359 7 : Measure* measure = score->firstMeasure();
2360 7 : bool mixChange = false;
2361 30 : for (size_t bar = 0; bar < measures; ++bar, measure = measure->nextMeasure()) {
2362 23 : const GpBar& gpbar = bars[bar];
2363 :
2364 23 : if (!gpbar.marker.isEmpty()) {
2365 0 : Segment* segment = measure->getSegment(SegmentType::ChordRest, measure->tick());
2366 0 : RehearsalMark* s = new RehearsalMark(segment);
2367 0 : s->setPlainText(gpbar.marker.trimmed());
2368 0 : s->setTrack(0);
2369 0 : segment->add(s);
2370 : }
2371 :
2372 23 : std::vector<Tuplet*> tuplets(staves);
2373 46 : for (size_t staffIdx = 0; staffIdx < staves; ++staffIdx) {
2374 23 : tuplets[staffIdx] = 0;
2375 : }
2376 :
2377 46 : for (size_t staffIdx = 0; staffIdx < staves; ++staffIdx) {
2378 23 : Fraction measureLen = { 0, 1 };
2379 23 : track_idx_t track = staffIdx * VOICES;
2380 23 : Fraction fraction = measure->tick();
2381 23 : int beats = readInt();
2382 23 : if (beats > 200) {
2383 0 : return false;
2384 : }
2385 114 : for (int beat = 0; beat < beats; ++beat) {
2386 91 : bool hasSlur = false;
2387 91 : bool hasLetRing = false;
2388 91 : bool hasPalmMute = false;
2389 91 : bool hasVibratoLeftHand = false;
2390 91 : bool hasVibratoWTremBar = false;
2391 :
2392 : // int pause = 0;
2393 91 : uint8_t beatBits = readUInt8();
2394 91 : bool dotted = beatBits & BEAT_DOTTED;
2395 91 : if (beatBits & BEAT_PAUSE) {
2396 : /*pause =*/
2397 8 : readUInt8();
2398 : }
2399 :
2400 91 : slide = -1;
2401 91 : if (muse::contains(slides, static_cast<int>(track))) {
2402 0 : slide = muse::take(slides, static_cast<int>(track));
2403 : }
2404 :
2405 91 : int len = readChar();
2406 91 : int tuple = 0;
2407 91 : if (beatBits & BEAT_TUPLET) {
2408 0 : tuple = readInt();
2409 : }
2410 :
2411 91 : Segment* segment = measure->getSegment(SegmentType::ChordRest, fraction);
2412 91 : if (beatBits & BEAT_CHORD) {
2413 0 : int numStrings = static_cast<int>(score->staff(staffIdx)->part()->instrument()->stringData()->strings());
2414 0 : int header = readUInt8();
2415 0 : String name;
2416 0 : if ((header & 1) == 0) {
2417 0 : name = readDelphiString();
2418 0 : readChord(segment, static_cast<int>(track), numStrings, name, false);
2419 : } else {
2420 0 : skip(25);
2421 0 : name = readPascalString(34);
2422 0 : readChord(segment, static_cast<int>(track), numStrings, name, false);
2423 0 : skip(36);
2424 : }
2425 0 : }
2426 91 : Lyrics* lyrics = 0;
2427 91 : if (beatBits & BEAT_LYRICS) {
2428 0 : String txt = readDelphiString();
2429 0 : Lyrics* lyrics2 = Factory::createLyrics(score->dummy());
2430 0 : lyrics2->setPlainText(txt);
2431 0 : }
2432 91 : int beatEffects = 0;
2433 :
2434 91 : if (beatBits & BEAT_EFFECTS) {
2435 0 : beatEffects = readBeatEffects(static_cast<int>(track), segment);
2436 : }
2437 91 : bool vibrato = beatEffects & 0x1 || beatEffects & 0x2;
2438 :
2439 91 : if (beatBits & BEAT_MIX_CHANGE) {
2440 1 : readMixChange(measure);
2441 1 : mixChange = true;
2442 : }
2443 :
2444 91 : int strings = readUInt8(); // used strings mask
2445 :
2446 91 : Fraction l = len2fraction(len);
2447 :
2448 : // Some beat effects could add a Chord before this
2449 91 : ChordRest* cr = segment->cr(track);
2450 : // if (!pause || strings)
2451 91 : if (strings) {
2452 83 : if (!segment->cr(track)) {
2453 83 : cr = Factory::createChord(segment);
2454 : }
2455 : } else {
2456 8 : if (segment->cr(track)) {
2457 0 : segment->remove(segment->cr(track));
2458 0 : delete cr;
2459 0 : cr = 0;
2460 : }
2461 8 : cr = Factory::createRest(segment);
2462 : }
2463 :
2464 91 : cr->setTrack(track);
2465 91 : if (lyrics) {
2466 0 : cr->add(lyrics);
2467 : }
2468 :
2469 91 : TDuration d(l);
2470 91 : d.setDots(dotted ? 1 : 0);
2471 :
2472 91 : if (dotted) {
2473 1 : l = l + (l * Fraction(1, 2));
2474 : }
2475 :
2476 91 : if (tuple) {
2477 0 : Tuplet* tuplet = tuplets[staffIdx];
2478 0 : if ((tuplet == 0) || (tuplet->elementsDuration() == tuplet->baseLen().fraction() * tuplet->ratio().numerator())) {
2479 0 : tuplet = Factory::createTuplet(measure);
2480 0 : tuplet->setTick(fraction);
2481 0 : tuplet->setTrack(cr->track());
2482 0 : tuplets[staffIdx] = tuplet;
2483 0 : setTuplet(tuplet, tuple);
2484 : }
2485 0 : tuplet->setTrack(track);
2486 0 : tuplet->setBaseLen(l);
2487 0 : tuplet->setTicks(l * tuplet->ratio().denominator());
2488 0 : cr->setTuplet(tuplet);
2489 0 : tuplet->add(cr);
2490 : }
2491 :
2492 91 : cr->setTicks(l);
2493 :
2494 91 : if (cr->isRest() && l >= measure->ticks()) {
2495 1 : cr->setDurationType(DurationType::V_MEASURE);
2496 1 : cr->setTicks(measure->ticks());
2497 : } else {
2498 90 : cr->setDurationType(d);
2499 : }
2500 :
2501 91 : if (!segment->cr(track)) {
2502 91 : segment->add(cr);
2503 : }
2504 :
2505 91 : Staff* staff = cr->staff();
2506 91 : int numStrings = static_cast<int>(staff->part()->instrument()->stringData()->strings());
2507 728 : for (int i = 6; i >= 0; --i) {
2508 637 : if (strings & (1 << i) && ((6 - i) < numStrings)) {
2509 87 : Note* note = Factory::createNote(toChord(cr));
2510 87 : toChord(cr)->add(note);
2511 87 : if (vibrato) {
2512 0 : hasVibratoLeftHand = true;
2513 : }
2514 87 : if (dotted) {
2515 1 : NoteDot* dot = Factory::createNoteDot(note);
2516 : // there is at most one dotted note in this guitar pro version - set 0 index
2517 1 : dot->setTrack(track); // needed to know the staff it belongs to (and detect tablature)
2518 1 : dot->setVisible(true);
2519 1 : note->add(dot);
2520 : }
2521 87 : ReadNoteResult readResult = readNote(6 - i, note);
2522 87 : hasSlur = readResult.slur || hasSlur;
2523 87 : hasLetRing = readResult.letRing || hasLetRing;
2524 87 : hasPalmMute = readResult.palmMute || hasPalmMute;
2525 87 : hasVibratoLeftHand = readResult.vibrato || hasVibratoLeftHand;
2526 87 : note->setTpcFromPitch();
2527 : }
2528 : }
2529 91 : if (cr && cr->isChord() && toChord(cr)->notes().empty()) {
2530 0 : if (segment->cr(track)) {
2531 0 : segment->remove(cr);
2532 : }
2533 0 : delete cr;
2534 0 : cr = Factory::createRest(segment);
2535 0 : cr->setTicks(l);
2536 0 : cr->setTrack(track);
2537 0 : cr->setDurationType(d);
2538 0 : segment->add(cr);
2539 : }
2540 91 : createSlur(hasSlur, staffIdx, cr);
2541 :
2542 91 : if (cr && (cr->isChord())) {
2543 83 : if (beatEffects >= 200) {
2544 0 : beatEffects -= 200;
2545 0 : Articulation* art = Factory::createArticulation(cr);
2546 0 : art->setSymId(SymId::guitarFadeOut);
2547 0 : art->setAnchor(ArticulationAnchor::TOP);
2548 0 : art->setPropertyFlags(Pid::ARTICULATION_ANCHOR, PropertyFlags::UNSTYLED);
2549 0 : if (!EditChord::toggleArticulation(score, cr, art)) {
2550 0 : delete art;
2551 : }
2552 : }
2553 :
2554 83 : bool hasVibratoLeftHandOnBeat = false;
2555 83 : bool hasVibratoWTremBarOnBeat = false;
2556 83 : applyBeatEffects(toChord(cr), beatEffects, hasVibratoLeftHandOnBeat, hasVibratoWTremBarOnBeat);
2557 83 : hasVibratoLeftHand = hasVibratoLeftHand || hasVibratoLeftHandOnBeat;
2558 83 : hasVibratoWTremBar = hasVibratoWTremBar || hasVibratoWTremBarOnBeat;
2559 83 : if (slide > 0) {
2560 0 : createSlide(slide, cr, static_cast<int>(staffIdx));
2561 : }
2562 : }
2563 :
2564 91 : if (cr) {
2565 91 : addLetRing(cr, hasLetRing);
2566 91 : addPalmMute(cr, hasPalmMute);
2567 91 : addVibratoLeftHand(cr, hasVibratoLeftHand);
2568 91 : addVibratoWTremBar(cr, hasVibratoWTremBar);
2569 : }
2570 :
2571 91 : restsForEmptyBeats(segment, measure, cr, l, static_cast<int>(track), fraction);
2572 91 : fraction += cr->actualTicks();
2573 91 : measureLen += cr->actualTicks();
2574 : }
2575 23 : if (measureLen < measure->ticks()) {
2576 0 : score->setRest(fraction, track, measure->ticks() - measureLen, false, nullptr, false);
2577 0 : m_continiousElementsBuilder->notifyUncompletedMeasure();
2578 : }
2579 23 : bool removeRests = true;
2580 23 : int counter = 0;
2581 23 : Rest* lastRest = nullptr;
2582 44 : for (auto seg = measure->first(); seg; seg = seg->next()) {
2583 43 : if (seg->segmentType() == SegmentType::ChordRest) {
2584 29 : auto cr = seg->cr(track);
2585 29 : if (cr && cr->isChord()) {
2586 22 : removeRests = false;
2587 22 : break;
2588 7 : } else if (cr) {
2589 7 : ++counter;
2590 7 : lastRest = toRest(cr);
2591 : }
2592 : }
2593 : }
2594 23 : if (removeRests && counter < 2) {
2595 1 : removeRests = false;
2596 1 : if (counter == 1) {
2597 1 : lastRest->setTicks(measure->timesig());
2598 1 : lastRest->setDurationType(DurationType::V_MEASURE);
2599 : }
2600 : }
2601 23 : if (removeRests) {
2602 0 : auto seg = measure->first();
2603 0 : while (seg && seg != measure->last())
2604 : {
2605 0 : if (seg->segmentType() == SegmentType::ChordRest) {
2606 0 : auto cr = seg->cr(track);
2607 0 : if (cr) {
2608 0 : seg->remove(cr);
2609 0 : delete cr;
2610 : }
2611 : }
2612 0 : seg = seg->next();
2613 : }
2614 0 : auto cr = Factory::createRest(seg);
2615 0 : cr->setTicks(measure->timesig());
2616 0 : cr->setDurationType(DurationType::V_MEASURE);
2617 0 : cr->setTrack(track);
2618 0 : seg->add(cr);
2619 : }
2620 : }
2621 23 : if (bar == 1 && !mixChange) {
2622 4 : setTempo(temp, score->firstMeasure());
2623 : }
2624 23 : }
2625 8 : for (auto n : slideList) {
2626 1 : auto segment = n->chord()->segment();
2627 1 : auto measure1 = segment->measure();
2628 1 : while ((segment = segment->next1(SegmentType::ChordRest))
2629 1 : || ((measure1 = measure1->nextMeasure()) && (segment = measure1->first()))) {
2630 : // bool br = false;
2631 1 : auto crest = segment->cr(n->track());
2632 1 : if (!crest) {
2633 0 : continue;
2634 : }
2635 1 : if (crest->type() == mu::engraving::ElementType::REST) {
2636 0 : break;
2637 : }
2638 1 : auto cr = toChord(crest);
2639 1 : if (!cr) {
2640 0 : continue;
2641 : }
2642 1 : if (cr->graceNotes().size()) {
2643 0 : cr = cr->graceNotes().front();
2644 : }
2645 1 : if (cr) {
2646 1 : for (auto nt : cr->notes()) {
2647 1 : if (nt->string() == n->string()) {
2648 : // auto mg = nt->magS();
2649 1 : Glissando* s = new Glissando(n);
2650 1 : s->setStartElement(n);
2651 1 : s->setTick(n->chord()->segment()->tick());
2652 1 : s->setTrack(n->track());
2653 1 : s->setGlissandoType(GlissandoType::STRAIGHT);
2654 1 : s->setEndElement(nt);
2655 1 : s->setTick2(cr->segment()->tick());
2656 1 : s->setTrack2(n->track());
2657 1 : score->addElement(s);
2658 1 : break;
2659 : }
2660 : }
2661 : }
2662 1 : break;
2663 : }
2664 : }
2665 :
2666 7 : m_continiousElementsBuilder->addElementsToScore();
2667 7 : m_guitarBendImporter->addElementsToScore();
2668 7 : addTunings();
2669 :
2670 7 : return true;
2671 7 : }
2672 :
2673 : //---------------------------------------------------------
2674 : // readBeatEffects
2675 : //---------------------------------------------------------
2676 :
2677 0 : int GuitarPro3::readBeatEffects(int track, Segment* segment)
2678 : {
2679 0 : int effects = 0;
2680 0 : uint8_t fxBits = readUInt8();
2681 :
2682 0 : if (fxBits & BEAT_EFFECT) {
2683 0 : effects = readUInt8(); // effect 1-tapping, 2-slapping, 3-popping
2684 0 : readInt(); // we don't need this integer
2685 : }
2686 :
2687 0 : if (fxBits & BEAT_ARPEGGIO) {
2688 0 : int strokeup = readUInt8(); // up stroke length
2689 0 : int strokedown = readUInt8(); // down stroke length
2690 :
2691 0 : Arpeggio* a = Factory::createArpeggio(score->dummy());
2692 0 : if (strokeup > 0) {
2693 0 : a->setArpeggioType(ArpeggioType::UP_STRAIGHT);
2694 0 : } else if (strokedown > 0) {
2695 0 : a->setArpeggioType(ArpeggioType::DOWN_STRAIGHT);
2696 : } else {
2697 0 : delete a;
2698 0 : a = 0;
2699 : }
2700 :
2701 0 : if (a) {
2702 0 : ChordRest* cr = Factory::createChord(segment);
2703 0 : cr->setTrack(track);
2704 0 : cr->add(a);
2705 0 : segment->add(cr);
2706 : }
2707 : }
2708 0 : if (fxBits & BEAT_TREMOLO) {
2709 : }
2710 0 : if (fxBits & BEAT_FADE) {
2711 0 : effects += 200;
2712 : }
2713 0 : if (fxBits & BEAT_DOTTED) {
2714 : }
2715 0 : if (fxBits & BEAT_CHORD) {
2716 : }
2717 0 : if (effects == 0) {
2718 0 : return fxBits;
2719 : }
2720 0 : return effects;
2721 : }
2722 :
2723 : //---------------------------------------------------------
2724 : // readTremoloBar
2725 : //---------------------------------------------------------
2726 :
2727 3 : void GuitarPro::readTremoloBar(int /*track*/, Segment* /*segment*/)
2728 : {
2729 : /*int a1 =*/
2730 3 : readChar();
2731 3 : /*int a2 =*/ readChar();
2732 3 : /*int a3 =*/ readChar();
2733 3 : /*int a4 =*/ readChar();
2734 3 : /*int a5 =*/ readChar();
2735 3 : int n = readInt();
2736 3 : std::vector<PitchValue> points;
2737 12 : for (int i = 0; i < n; ++i) {
2738 9 : int time = readInt();
2739 9 : int pitch = readInt();
2740 9 : int vibrato = readUInt8();
2741 9 : points.push_back(PitchValue(time, pitch, vibrato));
2742 : }
2743 3 : }
2744 :
2745 33 : void GuitarPro::addTunings()
2746 : {
2747 33 : const Measure* m = score->firstMeasure();
2748 :
2749 : // NOTE: GP doesn't support multiple tunings on one part
2750 : // We're safe to just take the very first chord rest segment
2751 : // and check if it has any non-standard tuning
2752 33 : const Fraction& frac{ 0, 1 };
2753 :
2754 66 : for (auto p : score->parts()) {
2755 66 : for (auto s : p->staves()) {
2756 33 : if (!s->isPrimaryStaff() || p->instrument()->useDrumset()) {
2757 31 : continue;
2758 : }
2759 :
2760 33 : Segment* seg = m->findSegment(SegmentType::ChordRest, frac);
2761 :
2762 33 : IF_ASSERT_FAILED(seg) {
2763 0 : LOGE() << "First measure MUST has a chord rest segment after import";
2764 0 : break;
2765 : }
2766 :
2767 33 : const StringData sd = *p->instrument()->stringData();
2768 33 : std::vector<int> tuning(sd.strings());
2769 230 : for (size_t i = 0; i < tuning.size(); ++i) {
2770 197 : tuning[i] = sd.stringList().at(i).pitch + p->instrument()->transpose().chromatic;
2771 : }
2772 :
2773 33 : if (utils::isStandardTuning(p->instrument()->channel(0)->program(), tuning)) {
2774 31 : continue;
2775 : }
2776 :
2777 2 : StringTunings* tun = Factory::createStringTunings(seg);
2778 2 : tun->setStringData(sd);
2779 2 : tun->setTrack(staff2track(s->idx()));
2780 2 : seg->add(tun);
2781 : // Instrument string data should be set to the standard
2782 2 : tuning = utils::standardTuningFor(p->instrument()->channel(0)->program(), (int)sd.strings());
2783 2 : StringData instrumentSD(sd.frets(), (int)tuning.size(), tuning.data());
2784 2 : p->instrument()->setStringData(instrumentSD);
2785 64 : }
2786 : }
2787 33 : }
2788 :
2789 : //---------------------------------------------------------
2790 : // addMetaInfo
2791 : //---------------------------------------------------------
2792 :
2793 73 : static void addMetaInfo(MasterScore* score, GuitarPro* gp, bool experimental)
2794 : {
2795 219 : std::vector<String> fieldNames = { gp->title, gp->subtitle, gp->artist,
2796 511 : gp->album, gp->composer };
2797 :
2798 : bool createTitleField
2799 410 : = std::any_of(fieldNames.begin(), fieldNames.end(), [](const String& fieldName) { return !fieldName.isEmpty(); });
2800 :
2801 73 : if (!createTitleField && !experimental) {
2802 64 : return;
2803 : }
2804 :
2805 9 : MeasureBase* m = nullptr;
2806 9 : if (!score->measures()->first()) {
2807 0 : m = Factory::createTitleVBox(score);
2808 0 : score->measures()->append(m);
2809 : } else {
2810 9 : m = score->measures()->first();
2811 9 : if (!m->isVBox()) {
2812 9 : MeasureBase* mb = Factory::createTitleVBox(score);
2813 9 : score->addMeasure(mb, m);
2814 9 : m = mb;
2815 : }
2816 : }
2817 9 : if (!gp->title.isEmpty() || experimental) {
2818 9 : Text* s = Factory::createText(m, TextStyleType::TITLE);
2819 9 : s->setPlainText(gp->title);
2820 9 : m->add(s);
2821 : }
2822 9 : if (!gp->subtitle.isEmpty() || !gp->artist.isEmpty() || !gp->album.isEmpty() || experimental) {
2823 4 : Text* s = Factory::createText(m, TextStyleType::SUBTITLE);
2824 4 : String str;
2825 4 : if (!gp->subtitle.isEmpty()) {
2826 1 : str.append(gp->subtitle);
2827 : }
2828 4 : if (!gp->artist.isEmpty()) {
2829 2 : if (!str.isEmpty()) {
2830 1 : str.append(u'\n');
2831 : }
2832 2 : str.append(gp->artist);
2833 : }
2834 4 : if (!gp->album.isEmpty()) {
2835 2 : if (!str.isEmpty()) {
2836 2 : str.append(u'\n');
2837 : }
2838 2 : str.append(gp->album);
2839 : }
2840 4 : s->setPlainText(str);
2841 4 : m->add(s);
2842 4 : }
2843 9 : if (!gp->composer.isEmpty()) {
2844 3 : Text* s = Factory::createText(m, TextStyleType::COMPOSER);
2845 3 : s->setPlainText(gp->composer);
2846 3 : m->add(s);
2847 : }
2848 :
2849 9 : if (!gp->poet.isEmpty() || experimental) {
2850 3 : Text* s = Factory::createText(m, TextStyleType::LYRICIST);
2851 3 : if (!gp->poet.isEmpty()) {
2852 1 : s->setPlainText(muse::mtrc("iex_guitarpro", "Words by %1").arg(gp->poet));
2853 : }
2854 :
2855 3 : m->add(s);
2856 : }
2857 146 : }
2858 :
2859 : //---------------------------------------------------------
2860 : // importGTP
2861 : //---------------------------------------------------------
2862 :
2863 301 : Err importGTP(MasterScore* score, muse::io::IODevice* io, const muse::modularity::ContextPtr& iocCtx, bool experimental)
2864 : {
2865 301 : if (!io->open(IODevice::ReadOnly)) {
2866 0 : return Err::FileOpenError;
2867 : }
2868 :
2869 301 : score->checkChordList();
2870 301 : io->seek(0);
2871 : char header[5];
2872 301 : io->read((uint8_t*)(header), 4);
2873 301 : header[4] = 0;
2874 301 : io->seek(0);
2875 301 : if (strcmp(header, "ptab") == 0) {
2876 3 : PowerTab ptb(io, score);
2877 3 : return ptb.read();
2878 3 : }
2879 :
2880 298 : GuitarPro* gp = nullptr;
2881 298 : bool readResult = false;
2882 298 : bool isVersionAbove6 = false;
2883 : // check to see if we are dealing with a GP file via the extension
2884 298 : if (strcmp(header, "PK\x3\x4") == 0) {
2885 145 : gp = new GuitarPro7(score, iocCtx);
2886 145 : readResult = gp->read(io);
2887 145 : gp->setTempo(0, 0);
2888 145 : isVersionAbove6 = true;
2889 : }
2890 : // check to see if we are dealing with a GPX file via the extension
2891 153 : else if (strcmp(header, "BCFZ") == 0) {
2892 76 : gp = new GuitarPro6(score, iocCtx);
2893 76 : drumset::initGuitarProDrumset();
2894 76 : readResult = gp->read(io);
2895 76 : gp->setTempo(0, 0);
2896 76 : isVersionAbove6 = true;
2897 : }
2898 : // otherwise it's an older version - check the header
2899 77 : else if (strcmp(&header[1], "FIC") == 0) {
2900 : uint8_t l;
2901 76 : io->read((uint8_t*)&l, 1);
2902 : char ss[30];
2903 76 : io->read((uint8_t*)(ss), 30);
2904 76 : ss[l] = 0;
2905 76 : String s = String::fromUtf8(ss);
2906 76 : if (s.startsWith(u"FICHIER GUITAR PRO ")) {
2907 75 : s = s.mid(20);
2908 1 : } else if (s.startsWith(u"FICHIER GUITARE PRO ")) {
2909 0 : s = s.mid(21);
2910 : } else {
2911 1 : LOGD("unknown gtp format <%s>", ss);
2912 1 : delete gp;
2913 1 : return Err::FileBadFormat;
2914 : }
2915 75 : int a = s.left(1).toInt();
2916 75 : int b = s.mid(2).toInt();
2917 75 : int version = a * 100 + b;
2918 75 : if (a == 1) {
2919 0 : gp = new GuitarPro1(score, version, iocCtx);
2920 75 : } else if (a == 2) {
2921 0 : gp = new GuitarPro2(score, version, iocCtx);
2922 75 : } else if (a == 3) {
2923 7 : gp = new GuitarPro3(score, version, iocCtx);
2924 68 : } else if (a == 4) {
2925 27 : gp = new GuitarPro4(score, version, iocCtx);
2926 41 : } else if (a == 5) {
2927 40 : gp = new GuitarPro5(score, version, iocCtx);
2928 : } else {
2929 1 : LOGD("unknown gtp format %d", version);
2930 1 : delete gp;
2931 1 : return Err::FileBadFormat;
2932 : }
2933 74 : readResult = gp->read(io);
2934 74 : gp->setTempo(0, 0);
2935 76 : } else {
2936 1 : delete gp;
2937 1 : return Err::FileBadFormat;
2938 : }
2939 295 : if (readResult == false) {
2940 1 : LOGD("guitar pro import error====");
2941 : // avoid another error message box
2942 1 : delete gp;
2943 1 : return Err::NoError;
2944 : }
2945 :
2946 294 : if (!isVersionAbove6) {
2947 73 : addMetaInfo(score, gp, experimental);
2948 : }
2949 :
2950 294 : int idx = 0;
2951 :
2952 526 : for (Measure* m1 = score->firstMeasure(); m1; m1 = m1->nextMeasure(), ++idx) {
2953 453 : if (gp->bars.empty()) {
2954 221 : break;
2955 : }
2956 232 : const GpBar& bar = gp->bars[idx];
2957 232 : if (bar.barLine != BarLineType::NORMAL && bar.barLine != BarLineType::END_REPEAT && bar.barLine != BarLineType::START_REPEAT
2958 1 : && bar.barLine != BarLineType::END_START_REPEAT) {
2959 1 : m1->setEndBarLineType(bar.barLine, 0);
2960 : }
2961 : }
2962 294 : if (score->lastMeasure() && score->lastMeasure()->endBarLineType() != BarLineType::NORMAL) {
2963 0 : score->lastMeasure()->setEndBarLineType(BarLineType::END, false);
2964 : }
2965 :
2966 611 : for (Part* part : score->parts()) {
2967 651 : for (const auto& pair : part->instruments()) {
2968 334 : pair.second->updateInstrumentId();
2969 : }
2970 : }
2971 :
2972 294 : score->updateTicksAndTimeSigMap();
2973 611 : for (Part* p : score->parts()) {
2974 317 : p->updateHarmonyChannels(false);
2975 : }
2976 :
2977 294 : delete gp;
2978 :
2979 294 : return Err::NoError;
2980 : }
2981 : } // namespace mu::iex::guitarpro
|