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 "containers.h"
26 :
27 : #include "engraving/dom/arpeggio.h"
28 : #include "engraving/dom/articulation.h"
29 : #include "engraving/dom/barline.h"
30 : #include "engraving/dom/bracket.h"
31 : #include "engraving/dom/chord.h"
32 : #include "engraving/dom/chordline.h"
33 : #include "engraving/dom/clef.h"
34 : #include "engraving/dom/dynamic.h"
35 : #include "engraving/dom/excerpt.h"
36 : #include "engraving/dom/factory.h"
37 : #include "engraving/dom/fingering.h"
38 : #include "engraving/dom/glissando.h"
39 : #include "engraving/dom/guitarbend.h"
40 : #include "engraving/dom/instrtemplate.h"
41 : #include "engraving/dom/keysig.h"
42 : #include "engraving/dom/lyrics.h"
43 : #include "engraving/dom/masterscore.h"
44 : #include "engraving/dom/measure.h"
45 : #include "engraving/dom/measurebase.h"
46 : #include "engraving/dom/note.h"
47 : #include "engraving/dom/notedot.h"
48 : #include "engraving/dom/part.h"
49 : #include "engraving/dom/pitchspelling.h"
50 : #include "engraving/dom/rehearsalmark.h"
51 : #include "engraving/dom/rest.h"
52 : #include "engraving/dom/segment.h"
53 : #include "engraving/dom/slur.h"
54 : #include "engraving/dom/staff.h"
55 : #include "engraving/dom/stafftext.h"
56 : #include "engraving/dom/stafftype.h"
57 : #include "engraving/dom/stringdata.h"
58 : #include "engraving/dom/tempotext.h"
59 : #include "engraving/dom/tie.h"
60 : #include "engraving/dom/timesig.h"
61 : #include "engraving/dom/tremolosinglechord.h"
62 : #include "engraving/dom/tuplet.h"
63 : #include "engraving/dom/volta.h"
64 : #include "engraving/types/symid.h"
65 : #include "engraving/dom/stringtunings.h"
66 : #include "engraving/dom/capo.h"
67 :
68 : #include "engraving/editing/editchord.h"
69 :
70 : #include "guitarprodrumset.h"
71 : #include "utils.h"
72 :
73 : #include "log.h"
74 :
75 : using namespace muse::io;
76 : using namespace mu::engraving;
77 :
78 : namespace mu::iex::guitarpro {
79 2 : static TremoloType tremoloType(int division)
80 : {
81 : static const std::map<int, TremoloType> types {
82 : { 1, TremoloType::R8 },
83 : { 2, TremoloType::R16 },
84 : { 3, TremoloType::R32 }
85 4 : };
86 :
87 2 : auto it = types.find(division);
88 2 : if (it != types.end()) {
89 2 : return it->second;
90 : }
91 :
92 0 : LOGE() << "wrong tremolo type";
93 0 : return TremoloType::INVALID_TREMOLO;
94 : }
95 :
96 : static std::unordered_map<uint64_t, mu::engraving::StringData> stringDatas;
97 : //---------------------------------------------------------
98 : // readInfo
99 : //---------------------------------------------------------
100 :
101 40 : void GuitarPro5::readInfo()
102 : {
103 40 : title = readDelphiString();
104 40 : subtitle = readDelphiString();
105 40 : artist = readDelphiString();
106 40 : album = readDelphiString();
107 40 : composer = readDelphiString();
108 40 : poet = readDelphiString();
109 40 : String copyright = readDelphiString();
110 40 : if (!copyright.isEmpty()) {
111 1 : score->setMetaTag(u"copyright", copyright);
112 : }
113 :
114 40 : readDelphiString(); // transcriber
115 40 : readDelphiString(); // instructions
116 40 : int n = readInt();
117 50 : for (int i = 0; i < n; ++i) {
118 10 : comments.append(readDelphiString());
119 : }
120 40 : }
121 :
122 : //---------------------------------------------------------
123 : // readBeatEffects
124 : //---------------------------------------------------------
125 :
126 28 : int GuitarPro5::readBeatEffects(int track, Segment* segment)
127 : {
128 28 : int effects = 0;
129 :
130 28 : uint8_t fxBits1 = readUInt8();
131 28 : uint8_t fxBits2 = readUInt8();
132 28 : if (fxBits1 & BEAT_FADE) {
133 2 : effects = 4; // fade in
134 : }
135 28 : if (fxBits1 & BEAT_EFFECT) {
136 9 : int k = readUInt8();
137 9 : effects = k + effects * 100; // &effects;
138 : }
139 28 : if (fxBits1 & BEAT_VIBRATO_TREMOLO) {
140 6 : effects = 7 + effects * 100;
141 : }
142 28 : if (fxBits2 & BEAT_TREMOLO) {
143 3 : readTremoloBar(track, segment); // readBend();
144 : }
145 28 : if (fxBits2 & BEAT_RASGUEADO) {
146 4 : m_currentBeatHasRasgueado = true;
147 : }
148 28 : if (fxBits1 & BEAT_ARPEGGIO) {
149 2 : int strokeup = readUInt8(); // up stroke length
150 2 : int strokedown = readUInt8(); // down stroke length
151 :
152 2 : Arpeggio* a = Factory::createArpeggio(score->dummy());
153 : // representation is different in guitar pro 5 - the up/down order below is correct
154 2 : if (strokeup > 0) {
155 1 : a->setArpeggioType(ArpeggioType::DOWN_STRAIGHT);
156 1 : if (strokeup < 7) {
157 1 : a->setStretch(1.0 / std::pow(2, 6 - strokeup));
158 : }
159 1 : } else if (strokedown > 0) {
160 1 : a->setArpeggioType(ArpeggioType::UP_STRAIGHT);
161 1 : if (strokedown < 7) {
162 1 : a->setStretch(1.0 / std::pow(2, 6 - strokedown));
163 : }
164 : } else {
165 0 : delete a;
166 0 : a = 0;
167 : }
168 2 : if (a) {
169 2 : ChordRest* cr = Factory::createChord(segment);
170 2 : cr->setTrack(track);
171 2 : cr->add(a);
172 2 : segment->add(cr);
173 : }
174 : }
175 28 : if (fxBits2 & BEAT_STROKE_DIR) {
176 2 : effects = readChar(); // stroke pick direction
177 2 : effects += 4; //1 or 2 for effects becomes 4 or 5
178 : }
179 28 : return effects;
180 : }
181 :
182 : //---------------------------------------------------------
183 : // readPageSetup
184 : //---------------------------------------------------------
185 :
186 40 : void GuitarPro5::readPageSetup()
187 : {
188 40 : skip(version > 500 ? 49 : 30);
189 480 : for (int i = 0; i < 11; ++i) {
190 440 : skip(4);
191 440 : readBytePascalString();
192 : }
193 40 : }
194 :
195 : //---------------------------------------------------------
196 : // readBeat
197 : //---------------------------------------------------------
198 :
199 698 : Fraction GuitarPro5::readBeat(const Fraction& tick, int voice, Measure* measure, int staffIdx, Tuplet** tuplets,
200 : bool /*mixChange*/)
201 : {
202 698 : uint8_t beatBits = readUInt8();
203 698 : bool dotted = beatBits & BEAT_DOTTED;
204 698 : bool hasSlur = false;
205 698 : bool hasHammerOnPullOff = false;
206 698 : bool hasLetRing = false;
207 698 : bool hasPalmMute = false;
208 698 : bool hasTrill = false;
209 698 : bool hasVibratoLeftHand = false;
210 698 : bool hasVibratoWTremBar = false;
211 698 : bool hasHarmonicArtificial = false;
212 698 : bool hasHarmonicPinch = false;
213 698 : bool hasHarmonicTap = false;
214 698 : bool hasHarmonicSemi = false;
215 :
216 698 : m_currentBeatHasRasgueado = false;
217 :
218 698 : slide = -1;
219 698 : int track = staffIdx * VOICES + voice;
220 698 : if (muse::contains(slides, track)) {
221 0 : slide = muse::take(slides, track);
222 : }
223 :
224 698 : int pause = -1;
225 698 : if (beatBits & BEAT_PAUSE) {
226 243 : pause = readUInt8();
227 : }
228 :
229 : // readDuration
230 698 : int len = readChar();
231 698 : int tuple = 0;
232 698 : if (beatBits & BEAT_TUPLET) {
233 57 : tuple = readInt();
234 : }
235 :
236 698 : Segment* segment = measure->getSegment(SegmentType::ChordRest, tick);
237 698 : if (beatBits & BEAT_CHORD) {
238 3 : size_t numStrings = score->staff(staffIdx)->part()->instrument()->stringData()->strings();
239 3 : skip(17);
240 3 : String name;
241 : {
242 3 : uint8_t charsCount = readUInt8();
243 : char c[21];
244 3 : f->read((uint8_t*)(c), 21);
245 : // Just in case
246 3 : if (charsCount <= 20) {
247 3 : c[charsCount] = '\0';
248 : } else {
249 0 : c[20] = '\0';
250 : }
251 3 : name = String::fromUtf8(c);
252 : }
253 3 : skip(4);
254 : // no header to be read in the GP5 format - default to true.
255 3 : readChord(segment, staffIdx * VOICES, static_cast<int>(numStrings), name, true);
256 3 : skip(32);
257 3 : }
258 698 : Lyrics* lyrics = 0;
259 698 : String free_text;
260 698 : if (beatBits & BEAT_LYRICS) {
261 : /// it is not beat lirics, it is free text
262 0 : free_text = readDelphiString();
263 : }
264 :
265 698 : int beatEffects = 0;
266 698 : if (beatBits & BEAT_EFFECTS) {
267 28 : beatEffects = readBeatEffects(track, segment);
268 : }
269 :
270 698 : last_segment = segment;
271 698 : if (beatBits & BEAT_MIX_CHANGE) {
272 1 : readMixChange(measure);
273 : }
274 :
275 698 : int strings = readUInt8(); // used strings mask
276 :
277 698 : Fraction l = len2fraction(len);
278 :
279 : // Some beat effects could add a Chord before this
280 698 : ChordRest* cr = segment->cr(track);
281 698 : if (voice != 0 && pause == 0 && strings == 0) {
282 153 : cr = 0;
283 : } else {
284 545 : if (strings == 0) {
285 90 : if (cr) {
286 0 : segment->remove(cr);
287 0 : delete cr;
288 0 : cr = 0;
289 : }
290 90 : cr = Factory::createRest(segment);
291 : } else {
292 455 : if (!cr) {
293 453 : cr = Factory::createChord(segment);
294 : }
295 : }
296 545 : cr->setTrack(track);
297 :
298 545 : TDuration d(l);
299 545 : d.setDots(dotted ? 1 : 0);
300 :
301 545 : if (dotted) {
302 13 : l = l + (l * Fraction(1, 2));
303 : }
304 :
305 545 : if (tuple) {
306 57 : int track2 = staffIdx * 2 + voice;
307 57 : Tuplet* tuplet = tuplets[track2];
308 57 : if ((tuplet == nullptr) || (tuplet->elementsDuration() == tuplet->baseLen().fraction() * tuplet->ratio().numerator())) {
309 19 : tuplet = Factory::createTuplet(measure);
310 19 : tuplets[track2] = tuplet;
311 19 : setTuplet(tuplet, tuple);
312 : }
313 57 : tuplet->setTrack(cr->track());
314 57 : tuplet->setBaseLen(l);
315 57 : tuplet->setTick(tick);
316 57 : tuplet->setTicks(l * tuplet->ratio().denominator());
317 57 : cr->setTuplet(tuplet);
318 57 : tuplet->add(cr);
319 : }
320 :
321 545 : cr->setTicks(l);
322 545 : if (cr->isRest() && (pause == 0 || l >= measure->ticks())) {
323 8 : cr->setDurationType(DurationType::V_MEASURE);
324 8 : cr->setTicks(measure->ticks());
325 : } else {
326 537 : cr->setDurationType(d);
327 : }
328 :
329 545 : if (!segment->cr(track)) {
330 543 : segment->add(cr);
331 : }
332 :
333 545 : Staff* staff = cr->staff();
334 545 : size_t numStrings = staff->part()->instrument()->stringData()->strings();
335 :
336 545 : Note* _note = nullptr;
337 545 : std::vector<Note*> delnote;
338 4360 : for (int i = 6; i >= 0; --i) {
339 3815 : if (strings & (1 << i) && ((6 - i) < static_cast<int>(numStrings))) {
340 639 : Note* note = Factory::createNote(toChord(cr));
341 639 : _note = note;
342 639 : if (dotted) {
343 : // there is at most one dotted note in this guitar pro version
344 15 : NoteDot* dot = Factory::createNoteDot(note);
345 15 : dot->setTrack(track); // needed to know the staff it belongs to (and detect tablature)
346 15 : dot->setVisible(true);
347 15 : note->add(dot);
348 : }
349 639 : toChord(cr)->add(note);
350 :
351 639 : ReadNoteResult readResult = readNote(6 - i, note);
352 639 : hasSlur = readResult.slur || hasSlur;
353 639 : hasHammerOnPullOff = readResult.hammerOnPullOff || hasHammerOnPullOff;
354 639 : hasLetRing = readResult.letRing || hasLetRing;
355 639 : hasPalmMute = readResult.palmMute || hasPalmMute;
356 639 : hasTrill = readResult.trill || hasTrill;
357 639 : hasVibratoLeftHand = readResult.vibrato || hasVibratoLeftHand;
358 639 : hasHarmonicArtificial = readResult.harmonicArtificial || hasHarmonicArtificial;
359 639 : hasHarmonicPinch = readResult.harmonicPinch || hasHarmonicPinch;
360 639 : hasHarmonicTap = readResult.harmonicTap || hasHarmonicTap;
361 639 : hasHarmonicSemi = readResult.harmonicSemi || hasHarmonicSemi;
362 639 : if (!slideList.empty() && slideList.back() == nullptr) {
363 2 : slideList.back() = note;
364 2 : hasSlur = true;
365 : }
366 639 : if (note->fret() == -20) {
367 0 : delnote.push_back(note);
368 : } else {
369 639 : note->setTpcFromPitch(Prefer::SHARPS);
370 : }
371 : }
372 : }
373 545 : if (!delnote.empty()) {
374 0 : Chord* chord = toChord(cr);
375 0 : for (auto n : delnote) {
376 0 : chord->remove(n);
377 0 : delete n;
378 : }
379 0 : if (chord->notes().empty()) {
380 0 : if (chord->tuplet()) {
381 0 : chord->tuplet()->remove(chord);
382 : }
383 0 : chord->segment()->remove(chord);
384 0 : delete chord;
385 0 : cr = nullptr;
386 : }
387 0 : delnote.clear();
388 : }
389 545 : if (cr && cr->isChord()) {
390 455 : Chord* chord = toChord(cr);
391 455 : chord->sortNotes();
392 455 : mu::iex::guitarpro::utils::createGhostNoteParenGroups(chord);
393 : }
394 545 : createSlur(hasSlur, staffIdx, cr);
395 545 : if (lyrics) {
396 0 : cr->add(lyrics);
397 : }
398 545 : if (free_text.size() && _note) {
399 0 : addTextToNote(free_text, _note);
400 : }
401 545 : }
402 :
403 698 : int rr = readChar();
404 698 : if (cr && cr->isChord()) {
405 455 : Chord* chord = toChord(cr);
406 :
407 455 : bool hasVibratoLeftHandOnBeat = false;
408 455 : bool hasVibratoWTremBarOnBeat = false;
409 :
410 : do {
411 455 : applyBeatEffects(chord, beatEffects % 100, hasVibratoLeftHandOnBeat, hasVibratoWTremBarOnBeat);
412 455 : hasVibratoLeftHand = hasVibratoLeftHand || hasVibratoLeftHandOnBeat;
413 455 : hasVibratoWTremBar = hasVibratoWTremBar || hasVibratoWTremBarOnBeat;
414 455 : } while (beatEffects /= 100);
415 455 : if (rr == ARPEGGIO_DOWN) {
416 0 : chord->setStemDirection(DirectionV::DOWN);
417 455 : } else if (rr == ARPEGGIO_UP) {
418 0 : chord->setStemDirection(DirectionV::UP);
419 : }
420 : }
421 :
422 698 : if (cr) {
423 : // fixing gp5 bug with not storying let ring for tied notes
424 545 : if (hasLetRing) {
425 14 : m_letRingForChords.insert(cr);
426 : }
427 :
428 545 : addLetRing(cr, hasLetRing);
429 545 : addPalmMute(cr, hasPalmMute);
430 545 : addTrill(cr, hasTrill);
431 545 : addHammerOnPullOff(cr, hasHammerOnPullOff);
432 545 : addRasgueado(cr, m_currentBeatHasRasgueado);
433 545 : addVibratoLeftHand(cr, hasVibratoLeftHand);
434 545 : addVibratoWTremBar(cr, hasVibratoWTremBar);
435 545 : addHarmonicMarks(cr, hasHarmonicArtificial, hasHarmonicPinch, hasHarmonicTap, hasHarmonicSemi);
436 : }
437 :
438 698 : int r = readChar();
439 698 : if (r & 0x8) {
440 0 : int rrr = readChar();
441 0 : LOGD(" 3beat read 0x%02x", rrr);
442 : }
443 698 : if (cr && cr->isChord()) {
444 455 : if (toChord(cr)->notes().size() == 0) {
445 0 : segment->remove(cr);
446 0 : delete cr;
447 0 : cr = 0;
448 455 : } else if (slide > 0) {
449 0 : createSlide(slide, cr, staffIdx);
450 : }
451 : }
452 698 : restsForEmptyBeats(segment, measure, cr, l, track, tick);
453 1396 : return cr ? cr->actualTicks() : measure->ticks();
454 698 : }
455 :
456 : //---------------------------------------------------------
457 : // readMeasure
458 : //---------------------------------------------------------
459 :
460 143 : void GuitarPro5::readMeasure(Measure* measure, int staffIdx, Tuplet** tuplets, bool mixChange)
461 : {
462 429 : for (int voice = 0; voice < 2; ++voice) {
463 286 : Fraction measureLen = { 0, 1 };
464 286 : Fraction tick = measure->tick();
465 286 : int beats = readInt();
466 286 : if (beats > 100) {
467 0 : return;
468 : }
469 984 : for (int beat = 0; beat < beats; ++beat) {
470 698 : Fraction ticks = readBeat(tick, voice, measure, staffIdx, tuplets, mixChange);
471 698 : ++_beat_counter;
472 698 : tick += ticks;
473 698 : measureLen += ticks;
474 : }
475 286 : if (measureLen < measure->ticks()) {
476 9 : score->setRest(tick, staffIdx * VOICES + voice, measure->ticks() - measureLen, false, nullptr, false);
477 9 : m_continiousElementsBuilder->notifyUncompletedMeasure();
478 : }
479 : }
480 : }
481 :
482 : //---------------------------------------------------------
483 : // readMixChange
484 : //---------------------------------------------------------
485 :
486 1 : bool GuitarPro5::readMixChange(Measure* measure)
487 : {
488 : /*char patch =*/
489 1 : readChar();
490 1 : skip(16);
491 1 : signed char volume = readChar();
492 1 : signed char pan = readChar();
493 1 : signed char chorus = readChar();
494 1 : signed char reverb = readChar();
495 1 : signed char phase = readChar();
496 1 : signed char tremolo = readChar();
497 1 : readDelphiString(); // tempo name
498 :
499 1 : int temp = readInt();
500 1 : bool editedTempo = false;
501 1 : if (volume >= 0) {
502 0 : readChar();
503 : }
504 1 : if (pan >= 0) {
505 0 : readChar();
506 : }
507 1 : if (chorus >= 0) {
508 0 : readChar();
509 : }
510 1 : if (reverb >= 0) {
511 0 : readChar();
512 : }
513 :
514 1 : if (phase >= 0) {
515 0 : readChar();
516 : }
517 1 : if (tremolo >= 0) {
518 0 : readChar();
519 : }
520 1 : if (temp >= 0) {
521 1 : if (temp != previousTempo) {
522 1 : if (last_segment && last_segment->tick() != measure->tick()) {
523 0 : bool hasTempoText = false;
524 0 : for (EngravingItem* e : last_segment->annotations()) {
525 0 : hasTempoText |= e->isTempoText();
526 : }
527 0 : if (!hasTempoText) {
528 0 : TempoText* tt = Factory::createTempoText(last_segment);
529 0 : tt->setTempo(BeatsPerSecond::fromBPM(temp));
530 0 : tt->setVisible(false);
531 0 : tt->setTrack(0);
532 0 : last_segment->add(tt);
533 : }
534 : }
535 1 : previousTempo = temp;
536 1 : setTempo(temp, measure);
537 1 : editedTempo = true;
538 : }
539 1 : last_segment = nullptr;
540 1 : readChar();
541 1 : if (version > 500) {
542 1 : readChar();
543 : }
544 : }
545 1 : readChar();
546 1 : readChar();
547 1 : if (version > 500) {
548 1 : readDelphiString();
549 1 : readDelphiString();
550 : }
551 1 : return editedTempo;
552 : }
553 :
554 : //---------------------------------------------------------
555 : // readTracks
556 : //---------------------------------------------------------
557 :
558 40 : bool GuitarPro5::readTracks()
559 : {
560 40 : stringDatas.clear();
561 85 : for (size_t i = 0; i < staves; ++i) {
562 : int tuning[GP_MAX_STRING_NUMBER];
563 45 : Staff* staff = score->staff(i);
564 45 : Part* part = staff->part();
565 :
566 45 : uint8_t c = readUInt8(); // simulations bitmask
567 45 : if (c & 0x2) { // 12 stringed guitar
568 : }
569 45 : if (c & 0x4) { // banjo track
570 : }
571 45 : if (i == 0 || version == 500) {
572 40 : skip(1);
573 : }
574 45 : String name = readPascalString(40);
575 :
576 45 : int strings = readInt();
577 45 : if (strings <= 0 || strings > GP_MAX_STRING_NUMBER) {
578 0 : return false;
579 : }
580 314 : for (int j = 0; j < strings; ++j) {
581 269 : tuning[j] = readInt();
582 : }
583 91 : for (int j = strings; j < GP_MAX_STRING_NUMBER; ++j) {
584 46 : readInt();
585 : }
586 45 : int midiPort = readInt() - 1;
587 45 : int midiChannel = readInt() - 1;
588 90 : if (midiChannel < 0 || midiChannel >= static_cast<int>(channelDefaults.size())) {
589 0 : LOGE() << "midiChannel " << midiChannel << " out of range 0-" << channelDefaults.size();
590 0 : return false;
591 : }
592 45 : /*int midiChannel2 =*/ readInt(); // -1
593 :
594 45 : int frets = readInt();
595 45 : int capo = readInt();
596 45 : /*int color =*/ readInt();
597 :
598 45 : skip(version > 500 ? 49 : 44);
599 45 : if (version > 500) {
600 : // british stack clean / amp tone
601 38 : readDelphiString();
602 38 : readDelphiString();
603 : }
604 45 : std::vector<int> tuning2(strings);
605 : //int tuning2[strings];
606 314 : for (int k = 0; k < strings; ++k) {
607 269 : tuning2[strings - k - 1] = tuning[k];
608 : }
609 45 : bool useFlats = createTuningString(strings, &tuning2[0]);
610 45 : StringData stringData(frets, strings, &tuning2[0], useFlats);
611 45 : Instrument* instr = part->instrument();
612 45 : instr->setStringData(stringData);
613 45 : instr->setSingleNoteDynamics(false);
614 45 : part->setPlainLongName(name);
615 45 : stringDatas.insert_or_assign(part->id().toUint64(), stringData);
616 :
617 : //
618 : // determine clef
619 : //
620 45 : int patch = channelDefaults[midiChannel].patch;
621 45 : ClefType clefId = ClefType::G;
622 45 : if (midiChannel == GP_DEFAULT_PERCUSSION_CHANNEL) {
623 1 : clefId = ClefType::PERC;
624 1 : StaffTypes type = StaffTypes::PERC_DEFAULT;
625 1 : if (auto it = drumset::PERC_STAFF_LINES_FROM_INSTRUMENT.find(name.toStdString());
626 1 : it != drumset::PERC_STAFF_LINES_FROM_INSTRUMENT.end()) {
627 0 : drumset::initGuitarProPercussionSet(it->second);
628 0 : drumset::setInstrumentDrumset(instr, it->second);
629 0 : switch (it->second.numLines) {
630 0 : case 1:
631 0 : type = StaffTypes::PERC_1LINE;
632 0 : break;
633 0 : case 2:
634 0 : type = StaffTypes::PERC_2LINE;
635 0 : break;
636 0 : case 3:
637 0 : type = StaffTypes::PERC_3LINE;
638 0 : break;
639 0 : default:
640 0 : type = StaffTypes::PERC_DEFAULT;
641 0 : break;
642 : }
643 : } else {
644 1 : drumset::initGuitarProDrumset();
645 1 : instr->setDrumset(drumset::gpDrumset);
646 : }
647 1 : staff->setStaffType(Fraction(0, 1), *StaffType::preset(type));
648 : } else {
649 44 : clefId = defaultClef(patch);
650 : }
651 :
652 45 : Measure* measure = score->firstMeasure();
653 45 : if (measure->tick() != Fraction(0, 1)) {
654 0 : Segment* segment = measure->getSegment(SegmentType::HeaderClef, Fraction(0, 1));
655 :
656 0 : Clef* clef = Factory::createClef(segment);
657 0 : clef->setClefType(clefId);
658 0 : clef->setTrack(i * VOICES);
659 0 : segment->add(clef);
660 : } else {
661 45 : staff->setDefaultClefType(ClefTypeList(clefId, clefId));
662 : }
663 :
664 45 : if (capo > 0 && !engravingConfiguration()->guitarProImportExperimental()) {
665 2 : Segment* s = measure->getSegment(SegmentType::ChordRest, measure->tick());
666 2 : const size_t track = i * VOICES;
667 :
668 2 : CapoParams params;
669 2 : params.active = true;
670 2 : params.transposeMode = CapoParams::TransposeMode::TAB_ONLY;
671 2 : params.fretPosition = capo;
672 :
673 2 : Capo* capoEl = Factory::createCapo(s);
674 2 : capoEl->setTrack(track);
675 2 : capoEl->setParams(params);
676 2 : s->add(capoEl);
677 :
678 2 : staff->insertCapoParams({ 0, 1 }, params, true);
679 2 : }
680 :
681 45 : InstrChannel* ch = instr->channel(0);
682 45 : if (midiChannel == GP_DEFAULT_PERCUSSION_CHANNEL) {
683 1 : ch->setProgram(0);
684 1 : ch->setBank(128);
685 : } else {
686 44 : ch->setProgram(patch);
687 44 : ch->setBank(0);
688 : }
689 45 : ch->setVolume(channelDefaults[midiChannel].volume);
690 45 : ch->setPan(channelDefaults[midiChannel].pan);
691 45 : ch->setChorus(channelDefaults[midiChannel].chorus);
692 45 : ch->setReverb(channelDefaults[midiChannel].reverb);
693 45 : staff->part()->setMidiChannel(midiChannel, midiPort);
694 :
695 : // missing: phase, tremolo
696 45 : }
697 40 : skip(version == 500 ? 2 : 1);
698 :
699 40 : return true;
700 : }
701 :
702 : //---------------------------------------------------------
703 : // readMeasures
704 : //---------------------------------------------------------
705 :
706 40 : void GuitarPro5::readMeasures(int /*startingTempo*/)
707 : {
708 40 : Measure* measure = score->firstMeasure();
709 40 : bool mixChange = false;
710 169 : for (size_t bar = 0; bar < measures; ++bar, measure = measure->nextMeasure()) {
711 129 : const GpBar& gpbar = bars[bar];
712 :
713 129 : if (!gpbar.marker.isEmpty()) {
714 4 : Segment* segment = measure->getSegment(SegmentType::ChordRest, measure->tick());
715 4 : RehearsalMark* s = Factory::createRehearsalMark(segment);
716 4 : s->setType(RehearsalMark::Type::Additional);
717 4 : s->setPlainText(gpbar.marker.trimmed());
718 4 : s->setTrack(0);
719 4 : segment->add(s);
720 : }
721 :
722 129 : std::vector<Tuplet*> tuplets(staves * 2);
723 : //Tuplet* tuplets[staves * 2]; // two voices
724 415 : for (size_t track = 0; track < staves * 2; ++track) {
725 286 : tuplets[track] = 0;
726 : }
727 :
728 272 : for (size_t staffIdx = 0; staffIdx < staves; ++staffIdx) {
729 143 : _beat_counter = 0;
730 143 : readMeasure(measure, static_cast<int>(staffIdx), &tuplets[0], mixChange);
731 143 : if (!(((bar == (measures - 1)) && (staffIdx == (staves - 1))))) {
732 : /*int a = */
733 103 : readChar();
734 : }
735 : }
736 129 : if (bar == 1 && !mixChange) {
737 17 : setTempo(tempo, score->firstMeasure());
738 : }
739 129 : }
740 :
741 40 : if (!gpLyrics.segments.empty()) {
742 0 : size_t size = std::min(gpLyrics.segments.size(), gpLyrics.lyrics.size());
743 0 : for (size_t i = 0; i < size; ++i) {
744 0 : std::string str = gpLyrics.lyrics[i].toStdString();
745 0 : auto seg = gpLyrics.segments[i];
746 0 : auto mes = seg->measure();
747 0 : while (str.size() && seg && seg->segmentType() == SegmentType::ChordRest) {
748 0 : auto cr = seg->cr(gpLyrics.lyricTrack);
749 0 : if (cr) {
750 0 : if (str[0] != '-') {
751 0 : Lyrics* lyr = Factory::createLyrics(cr);
752 :
753 0 : std::string text;
754 0 : auto pos = str.find('-');
755 0 : auto pos2 = str.find('\n');
756 0 : if (pos2 < pos) {
757 0 : pos = pos2;
758 : }
759 0 : if (pos != std::string::npos) {
760 0 : const char* c = &str.c_str()[pos + 1];
761 0 : if (*c == 0) {
762 0 : pos = std::string::npos;
763 0 : text = str;
764 : } else {
765 0 : text = str.substr(0, pos);
766 0 : str = str.substr(pos + 1);
767 : }
768 : } else {
769 0 : text = str;
770 : }
771 0 : if (pos == std::string::npos) {
772 0 : str.resize(0);
773 : }
774 0 : lyr->setPlainText(String::fromStdString(text));
775 0 : cr->add(lyr);
776 0 : } else {
777 0 : str = str.substr(1);
778 : }
779 : }
780 0 : seg = seg->next();
781 0 : if (!seg) {
782 0 : mes = mes->nextMeasure();
783 0 : if (!mes) {
784 0 : break;
785 : }
786 0 : seg = mes->first();
787 : }
788 : }
789 0 : }
790 40 : } else if (gpLyrics.lyricTrack != 0) {
791 0 : size_t counter = 0;
792 0 : size_t index = 0;
793 0 : gpLyrics.lyricTrack -= 1;
794 0 : Measure* mes = score->firstMeasure();
795 0 : if (!mes) {
796 0 : return;
797 : }
798 :
799 0 : Segment* beg = mes->first();
800 :
801 : do {
802 0 : if (beg->segmentType() == SegmentType::ChordRest && beg->cr(gpLyrics.lyricTrack)) {
803 0 : ChordRest* cr = beg->cr(gpLyrics.lyricTrack);
804 0 : assert(cr);
805 0 : ++counter;
806 0 : if (!cr->isChord()) {
807 0 : continue;
808 : }
809 :
810 0 : bool isTied = false;
811 0 : Chord* chord = toChord(cr);
812 0 : for (Note* n : chord->notes()) {
813 0 : const auto& tiedNotes = n->tiedNotes();
814 :
815 0 : if (tiedNotes.size() > 1 && tiedNotes.front() != n) {
816 0 : isTied = true;
817 0 : break;
818 : }
819 0 : }
820 :
821 0 : if (isTied) {
822 0 : continue;
823 : }
824 :
825 0 : if (counter >= gpLyrics.fromBeat) {
826 0 : if (gpLyrics.lyricPos.size() == index) {
827 0 : gpLyrics.lyricPos.push_back(0);
828 : }
829 :
830 0 : String& lyricsInIndex = gpLyrics.lyrics[index];
831 0 : if (lyricsInIndex[0] != u'-') {
832 0 : Lyrics* lyr = mu::engraving::Factory::createLyrics(cr);
833 :
834 0 : String text;
835 0 : size_t pos = lyricsInIndex.indexOf(u'-', gpLyrics.lyricPos[index]);
836 0 : size_t pos2 = lyricsInIndex.indexOf(u'\n', gpLyrics.lyricPos[index]);
837 0 : if (pos2 < pos) {
838 0 : pos = pos2;
839 : }
840 :
841 0 : if (pos != std::string::npos && (pos + 1 < lyricsInIndex.size())) {
842 0 : const char16_t* c = &lyricsInIndex[pos + 1];
843 0 : if (*c == 0) {
844 0 : pos = std::string::npos;
845 0 : text = lyricsInIndex;
846 : } else {
847 0 : text = lyricsInIndex.mid(gpLyrics.lyricPos[index], pos + 1 - gpLyrics.lyricPos[index]);
848 0 : gpLyrics.lyricPos[index] = pos + 1;
849 : }
850 : } else {
851 0 : text = lyricsInIndex.mid(gpLyrics.lyricPos[index]);
852 : }
853 :
854 0 : if (pos == std::string::npos) {
855 0 : ++index;
856 : }
857 :
858 0 : lyr->setPlainText(text);
859 0 : cr->add(lyr);
860 0 : if (index >= gpLyrics.lyrics.size()) {
861 0 : break;
862 : }
863 0 : } else if (lyricsInIndex.size() >= 2) {
864 0 : lyricsInIndex = lyricsInIndex.mid(1);
865 : }
866 : }
867 : }
868 0 : } while ((beg = beg->next())
869 0 : || (mes->next() && mes->next()->isMeasure() && (mes = toMeasure(mes->next())) && (beg = mes->first())));
870 : }
871 : }
872 :
873 : //---------------------------------------------------------
874 : // read
875 : //---------------------------------------------------------
876 :
877 40 : bool GuitarPro5::read(IODevice* io)
878 : {
879 40 : m_continiousElementsBuilder = std::make_unique<ContiniousElementsBuilder>(score);
880 40 : m_guitarBendImporter = std::make_unique<GuitarBendImporter>(score);
881 :
882 40 : f = io;
883 :
884 40 : readInfo();
885 40 : readLyrics();
886 40 : readPageSetup();
887 :
888 40 : previousTempo = -1;
889 :
890 40 : tempo = readInt();
891 40 : if (version > 500) {
892 33 : skip(1);
893 : }
894 :
895 40 : key = readInt();
896 40 : /* int octave =*/ readChar(); // octave
897 :
898 40 : readChannels();
899 :
900 40 : std::vector<unsigned int> articulations;
901 40 : articulations.resize(19);
902 : {
903 : unsigned int r;
904 : unsigned char x;
905 800 : for (int i = 0; i < 19; ++i) {
906 760 : x = readUInt8();
907 760 : r = x;
908 760 : x = readUInt8();
909 760 : r += x << 8;
910 :
911 760 : articulations[i] = r;
912 : }
913 : }
914 :
915 : //skip(42);
916 40 : skip(4);
917 :
918 40 : measures = readInt();
919 40 : staves = readInt();
920 40 : initDynamics(staves);
921 :
922 320 : for (size_t str = 0; str < 7; ++str) {
923 595 : for (size_t staff = 0; staff < staves; ++staff) {
924 315 : dead_end[{ static_cast<int>(staff), static_cast<int>(str) }] = true;
925 : }
926 : }
927 :
928 40 : slurs.resize(staves, nullptr);
929 :
930 40 : int tnumerator = 4;
931 40 : int tdenominator = 4;
932 169 : for (size_t i = 0; i < measures; ++i) {
933 129 : if (i > 0) {
934 89 : skip(1);
935 : }
936 129 : GpBar bar;
937 129 : uint8_t barBits = readUInt8();
938 129 : if (barBits & SCORE_TIMESIG_NUMERATOR) {
939 40 : tnumerator = readUInt8();
940 : }
941 129 : if (barBits & SCORE_TIMESIG_DENOMINATOR) {
942 40 : tdenominator = readUInt8();
943 : }
944 129 : if (barBits & SCORE_REPEAT_START) {
945 0 : bar.repeatFlags = bar.repeatFlags | mu::engraving::Repeat::START;
946 : }
947 129 : if (barBits & SCORE_REPEAT_END) { // number of repeats
948 1 : bar.repeatFlags = bar.repeatFlags | mu::engraving::Repeat::END;
949 1 : bar.repeats = readUInt8();
950 : }
951 129 : if (barBits & SCORE_MARKER) {
952 4 : bar.marker = readDelphiString(); // new section?
953 4 : /*int color =*/ readInt(); // color?
954 : }
955 129 : if (barBits & SCORE_VOLTA) { // a volta
956 2 : uint8_t voltaNumber = readUInt8();
957 11 : while (voltaNumber > 0) {
958 : // voltas are represented as flags
959 9 : bar.volta.voltaType = GP_VOLTA_FLAGS;
960 9 : bar.volta.voltaInfo.push_back(voltaNumber & 1);
961 9 : voltaNumber >>= 1;
962 : }
963 2 : bar.repeats = static_cast<int>(bar.volta.voltaInfo.size()) + 1;
964 : }
965 129 : if (barBits & SCORE_KEYSIG) {
966 70 : int currentKey = readUInt8();
967 : /* key signatures are specified as
968 : * 1# = 1, 2# = 2, ..., 7# = 7
969 : * 1b = 255, 2b = 254, ... 7b = 249 */
970 70 : bar.keysig = currentKey <= 7 ? currentKey : -256 + currentKey;
971 70 : readUInt8(); // specified major/minor mode
972 : }
973 129 : if (barBits & SCORE_DOUBLE_BAR) {
974 0 : bar.barLine = BarLineType::DOUBLE;
975 : }
976 129 : if (barBits & 0x3) {
977 40 : skip(4);
978 : }
979 129 : if ((barBits & 0x10) == 0) {
980 127 : skip(1);
981 : }
982 :
983 129 : readChar(); // triple feel (none, 8, 16)
984 129 : bar.timesig = Fraction(tnumerator, tdenominator);
985 129 : bars.push_back(bar);
986 129 : }
987 :
988 : //
989 : // create a part for every staff
990 : //
991 85 : for (size_t staffIdx = 0; staffIdx < staves; ++staffIdx) {
992 45 : Part* part = new Part(score);
993 45 : Staff* s = Factory::createStaff(part);
994 :
995 45 : score->appendStaff(s);
996 45 : score->appendPart(part);
997 : }
998 :
999 40 : createMeasures();
1000 40 : if (!readTracks()) {
1001 0 : return false;
1002 : }
1003 40 : readMeasures(tempo);
1004 40 : const Measure* m = score->firstMeasure();
1005 :
1006 : // NOTE: GP doesn't support multiple tunings on one part
1007 : // We're safe to just take the very first chord rest segment
1008 : // and check if it has any non-standard tuning
1009 40 : const Fraction& frac{ 0, 1 };
1010 :
1011 85 : for (auto p : score->parts()) {
1012 90 : for (auto s : p->staves()) {
1013 45 : if (!s->isPrimaryStaff() || p->instrument()->useDrumset()) {
1014 41 : continue;
1015 : }
1016 :
1017 44 : Segment* seg = m->findSegment(SegmentType::ChordRest, frac);
1018 :
1019 44 : IF_ASSERT_FAILED(seg) {
1020 0 : LOGE() << "First measure MUST has a chord rest segment after import";
1021 0 : return false;
1022 : }
1023 :
1024 44 : if (stringDatas.find(p->id().toUint64()) == stringDatas.end()) {
1025 0 : continue;
1026 : }
1027 44 : StringData sd = stringDatas.at(p->id().toUint64());
1028 :
1029 44 : std::vector<int> tuningPitches(sd.strings());
1030 307 : for (size_t i = 0; i < tuningPitches.size(); ++i) {
1031 263 : tuningPitches[i] = sd.stringList().at(i).pitch + p->instrument()->transpose().chromatic;
1032 : }
1033 :
1034 44 : if (utils::isStandardTuning(p->instrument()->channel(0)->program(), tuningPitches)) {
1035 40 : continue;
1036 : }
1037 :
1038 4 : StringTunings* tun = Factory::createStringTunings(seg);
1039 4 : tun->setStringData(sd);
1040 4 : tun->setTrack(staff2track(s->idx()));
1041 4 : seg->add(tun);
1042 :
1043 4 : auto tuning = utils::standardTuningFor(p->instrument()->channel(0)->program(), (int)sd.strings());
1044 4 : sd = StringData(sd.frets(), (int)tuning.size(), tuning.data());
1045 4 : p->instrument()->setStringData(sd);
1046 84 : }
1047 : }
1048 43 : for (auto n : slideList) {
1049 3 : auto segment = n->chord()->segment();
1050 3 : auto measure = segment->measure();
1051 3 : while ((segment = segment->next1(SegmentType::ChordRest)) || ((measure = measure->nextMeasure()) && (segment = measure->first()))) {
1052 3 : if (segment->segmentType() != SegmentType::ChordRest) {
1053 0 : continue;
1054 : }
1055 3 : bool br = false;
1056 3 : ChordRest* cr = toChordRest(segment->cr(n->track()));
1057 3 : if (cr && cr->isChord()) {
1058 3 : Chord* c = toChord(cr);
1059 3 : for (auto nt : c->notes()) {
1060 3 : if (nt->string() == n->string()) {
1061 3 : for (auto e : nt->el()) {
1062 0 : if (e->isChordLine()) {
1063 0 : ChordLine* cl = toChordLine(e);
1064 0 : if (cl->chordLineType() == ChordLineType::PLOP || cl->chordLineType() == ChordLineType::SCOOP) {
1065 0 : br = true;
1066 0 : break;
1067 : }
1068 : }
1069 : }
1070 3 : if (br) {
1071 0 : break;
1072 : }
1073 :
1074 3 : m_glissandoNotePairs.push_back({ n, nt });
1075 3 : br = true;
1076 3 : break;
1077 : }
1078 : }
1079 : }
1080 3 : if (br) {
1081 3 : break;
1082 : }
1083 : }
1084 : }
1085 :
1086 40 : std::map<int, int> counter;
1087 800 : for (int i = 0; i < 19; ++i) {
1088 760 : if (articulations[i] != 0xFFFF) {
1089 0 : Measure* measure = toMeasure(score->measure(articulations[i] - 1));
1090 0 : if (i < 4) {
1091 0 : Segment* segment = measure->getSegment(SegmentType::BarLine, measure->tick());
1092 0 : Symbol* sym = new Symbol(measure);
1093 0 : if (i == 0) {
1094 0 : sym->setSym(SymId::coda);
1095 0 : } else if (i == 1) {
1096 0 : sym->setSym(SymId::codaSquare);
1097 0 : } else if (i == 2) {
1098 0 : sym->setSym(SymId::segno);
1099 : } else {
1100 0 : sym->setSym(SymId::segnoSerpent2);
1101 : }
1102 :
1103 0 : sym->setTrack(0);
1104 0 : segment->add(sym);
1105 0 : auto iter = counter.find(articulations[i]);
1106 0 : if (iter == counter.end()) {
1107 0 : counter[articulations[i]] = 1;
1108 : } else {
1109 0 : counter[articulations[i]] += 1;
1110 : }
1111 : } else {
1112 0 : Segment* s = measure->getSegment(SegmentType::KeySig, measure->tick());
1113 0 : StaffText* st = new StaffText(s);
1114 : static constexpr char text[][22] = {
1115 : "fine", "Da Capo", "D.C. al Coda", "D.C. al Doppia Coda",
1116 : "D.C. al Fine", "Da Segno", "D.S. al Coda", "D.S. al Doppia Coda",
1117 : "D.S. al Fine", "Da Doppio Segno", "D.D.S. al Coda", "D.D.S. al Doppia Coda",
1118 : "D.D.S. al Fine", "Da Coda", "Da Doppia Coda"
1119 : };
1120 0 : st->setPlainText(String::fromAscii(text[i - 4]));
1121 0 : st->setTrack(0);
1122 0 : auto iter = counter.find(articulations[i]);
1123 0 : if (iter == counter.end()) {
1124 0 : counter[articulations[i]] = 1;
1125 : } else {
1126 0 : counter[articulations[i]] += 1;
1127 : }
1128 0 : score->addElement(st);
1129 : }
1130 : }
1131 : }
1132 :
1133 40 : m_continiousElementsBuilder->addElementsToScore();
1134 40 : m_guitarBendImporter->addElementsToScore();
1135 40 : addGlissandos();
1136 40 : utils::addPlayCountTexts(score);
1137 :
1138 40 : return true;
1139 40 : }
1140 :
1141 : //---------------------------------------------------------
1142 : // readNoteEffects
1143 : //---------------------------------------------------------
1144 :
1145 89 : GuitarPro::ReadNoteResult GuitarPro5::readNoteEffects(Note* note)
1146 : {
1147 89 : ReadNoteResult result;
1148 89 : uint8_t modMask1 = readUInt8();
1149 89 : uint8_t modMask2 = readUInt8();
1150 89 : std::vector<PitchValue> bendData;
1151 89 : Note* bendParent = nullptr;
1152 :
1153 89 : if (modMask1 & EFFECT_BEND) {
1154 12 : bendData = readBendDataFromFile();
1155 12 : bendParent = note;
1156 : }
1157 89 : if (modMask1 & EFFECT_HAMMER) {
1158 3 : result.hammerOnPullOff = true;
1159 : }
1160 89 : if (modMask1 & EFFECT_LET_RING) {
1161 12 : result.letRing = true;
1162 : }
1163 :
1164 89 : if (modMask1 & EFFECT_GRACE) {
1165 5 : int fret = readUInt8(); // grace fret
1166 5 : /*int dynamic =*/ readUInt8(); // grace dynamic
1167 5 : int transition = readUInt8(); // grace transition
1168 5 : int duration = readUInt8(); // grace duration
1169 5 : int gflags = readUInt8();
1170 :
1171 5 : int grace_len = Constants::DIVISION / 8;
1172 5 : if (duration == 2) {
1173 1 : grace_len = Constants::DIVISION / 6; //24th
1174 4 : } else if (duration == 3) {
1175 2 : grace_len = Constants::DIVISION / 4; //16th
1176 : }
1177 5 : NoteType note_type = NoteType::ACCIACCATURA;
1178 :
1179 5 : if (gflags & NOTE_APPOGIATURA) { //on beat
1180 2 : note_type = NoteType::APPOGGIATURA;
1181 : }
1182 :
1183 5 : int grace_pitch = note->staff()->part()->instrument()->stringData()->getPitch(note->string(), fret, nullptr);
1184 :
1185 5 : auto gnote = score->setGraceNote(note->chord(), grace_pitch, note_type, grace_len);
1186 :
1187 : // gp5 not supports more than one grace note,
1188 : // so it's always should be shown as eight note
1189 5 : gnote->chord()->setDurationType(Fraction { 1, 8 });
1190 :
1191 5 : gnote->setString(note->string());
1192 5 : gnote->setFret(fret);
1193 5 : if (transition == 0) {
1194 : // no transition
1195 3 : } else if (transition == 1) {
1196 2 : } else if (transition == 3) {
1197 1 : Slur* slur1 = Factory::createSlur(score->dummy());
1198 1 : slur1->setStartElement(gnote->chord());
1199 1 : slur1->setEndElement(note->chord());
1200 1 : slur1->setOwnershipParent(0);
1201 1 : slur1->setTrack(note->staffIdx());
1202 1 : slur1->setTrack2(note->staffIdx());
1203 1 : slur1->setTick(gnote->chord()->tick());
1204 1 : slur1->setTick2(note->chord()->tick());
1205 1 : score->addElement(slur1);
1206 : //TODO: Add a 'slide' guitar effect when implemented
1207 : //note->setSlideNote(gn);
1208 : }
1209 : }
1210 89 : if (modMask2 & EFFECT_STACCATO) {
1211 0 : Chord* chord = note->chord();
1212 0 : Articulation* a = Factory::createArticulation(chord);
1213 0 : a->setSymId(SymId::articStaccatoAbove);
1214 0 : bool add = true;
1215 0 : for (auto a1 : chord->articulations()) {
1216 0 : if (a1->symId() == SymId::articStaccatoAbove) {
1217 0 : add = false;
1218 0 : break;
1219 : }
1220 : }
1221 0 : if (add) {
1222 0 : chord->add(a);
1223 : }
1224 : }
1225 89 : if (modMask2 & EFFECT_PALM_MUTE) {
1226 3 : result.palmMute = true;
1227 : }
1228 :
1229 89 : if (modMask2 & EFFECT_TREMOLO) { // tremolo picking length
1230 2 : int tremoloDivision = readUInt8();
1231 2 : if (tremoloDivision >= 1 && tremoloDivision <= 3) {
1232 2 : TremoloType type = tremoloType(tremoloDivision);
1233 2 : DO_ASSERT(!isTremoloTwoChord(type));
1234 2 : Chord* chord = note->chord();
1235 2 : TremoloSingleChord* t = Factory::createTremoloSingleChord(chord);
1236 2 : t->setTremoloType(type);
1237 2 : chord->add(t);
1238 2 : m_tremolosInChords[chord] = type;
1239 2 : } else {
1240 0 : LOGD("Unknown tremolo value");
1241 : }
1242 : }
1243 89 : if (modMask2 & EFFECT_SLIDE) {
1244 22 : int slideKind = readUInt8();
1245 22 : ChordLine* sld = nullptr;
1246 22 : ChordLineType slideType = ChordLineType::NOTYPE;
1247 :
1248 22 : if (slideKind & SLIDE_OUT_DOWN) {
1249 4 : slideKind &= ~SLIDE_OUT_DOWN;
1250 4 : sld = Factory::createChordLine(score->dummy());
1251 4 : slideType = ChordLineType::FALL;
1252 : }
1253 : // slide out upwards (doit)
1254 22 : if (slideKind & SLIDE_OUT_UP) {
1255 4 : slideKind &= ~SLIDE_OUT_UP;
1256 4 : sld = Factory::createChordLine(score->dummy());
1257 4 : slideType = ChordLineType::DOIT;
1258 : }
1259 : // slide in from below (plop)
1260 22 : if (slideKind & SLIDE_IN_BELOW) {
1261 4 : slideKind &= ~SLIDE_IN_BELOW;
1262 4 : sld = Factory::createChordLine(score->dummy());
1263 4 : slideType = ChordLineType::PLOP;
1264 : }
1265 : // slide in from above (scoop)
1266 22 : if (slideKind & SLIDE_IN_ABOVE) {
1267 4 : slideKind &= ~SLIDE_IN_ABOVE;
1268 4 : sld = Factory::createChordLine(score->dummy());
1269 4 : slideType = ChordLineType::SCOOP;
1270 : }
1271 :
1272 22 : if (sld) {
1273 16 : sld->setChordLineType(slideType);
1274 16 : sld->setStraight(true);
1275 16 : note->chord()->add(sld);
1276 16 : sld->setNote(note);
1277 : }
1278 :
1279 22 : if (slideKind & LEGATO_SLIDE) {
1280 2 : slideKind &= ~LEGATO_SLIDE;
1281 2 : slideList.push_back(nullptr);
1282 2 : createSlur(true, note->staffIdx(), note->chord());
1283 : }
1284 :
1285 22 : if (slideKind & SHIFT_SLIDE) {
1286 1 : slideKind &= ~SHIFT_SLIDE;
1287 1 : slideList.push_back(note);
1288 : }
1289 : }
1290 :
1291 89 : if (modMask2 & EFFECT_ARTIFICIAL_HARMONIC) {
1292 25 : int type = readChar();
1293 25 : if (type == HARMONIC_MARK_NATURAL) {
1294 0 : int fret = note->fret();
1295 :
1296 0 : note->setHarmonic(true);
1297 0 : float harmonicFret = naturalHarmonicFromFret(fret);
1298 0 : int harmonicOvertone = utils::harmonicOvertone(note, harmonicFret, type);
1299 0 : note->setDisplayFret(Note::DisplayFretOption::NaturalHarmonic);
1300 0 : note->setHarmonicFret(harmonicFret);
1301 0 : auto staff = note->staff();
1302 0 : int pitch = staff->part()->instrument()->stringData()->getPitch(note->string(), harmonicOvertone, staff, note->tick());
1303 :
1304 0 : note->setPitch(clampPitch(pitch));
1305 0 : note->setTpcFromPitch(Prefer::SHARPS);
1306 25 : } else if (type >= HARMONIC_MARK_ARTIFICIAL && type <= HARMONIC_MARK_SEMI) {
1307 25 : int fret = (type == HARMONIC_MARK_TAP ? (readChar() - note->fret()) : note->fret());
1308 25 : float midi = note->pitch() + fret;
1309 25 : int currentOctave = floor(midi / 12);
1310 25 : auto harmNote = (type == HARMONIC_MARK_ARTIFICIAL ? readChar() : 0);
1311 25 : if (type == HARMONIC_MARK_ARTIFICIAL) {
1312 19 : readChar();
1313 : }
1314 :
1315 25 : auto octave = currentOctave + (type == HARMONIC_MARK_ARTIFICIAL ? readChar() : 0);
1316 :
1317 25 : Note* harmonicNote = Factory::createNote(note->chord());
1318 :
1319 25 : harmonicNote->setHarmonic(true);
1320 25 : harmonicNote->setPlay(false);
1321 25 : note->setPlay(true);
1322 : /// @note option to show or not additional harmonic fret in "<>" to be implemented
1323 : ///harmonicNote->setDisplayFret(Note::DisplayFretOption::ArtificialHarmonic);
1324 : ///note->setDisplayFret(Note::DisplayFretOption::Hide);
1325 25 : harmonicNote->setDisplayFret(Note::DisplayFretOption::Hide);
1326 25 : m_harmonicNotes[note] = harmonicNote;
1327 :
1328 25 : Staff* staff = note->staff();
1329 25 : float harmonicFret = 0;
1330 25 : switch (static_cast<int>(((octave * 12) + harmNote) - midi)) {
1331 0 : case 4:
1332 0 : harmonicFret = 12;
1333 0 : break;
1334 0 : case 11:
1335 0 : harmonicFret = 7;
1336 0 : break;
1337 0 : case 16:
1338 0 : harmonicFret = 5;
1339 0 : break;
1340 1 : case 20:
1341 1 : harmonicFret = 4;
1342 1 : break;
1343 0 : case 23:
1344 0 : harmonicFret = 3.2f;
1345 0 : break;
1346 0 : case 25:
1347 0 : harmonicFret = 2.7f;
1348 0 : break;
1349 0 : case 28:
1350 0 : harmonicFret = 2.4f;
1351 0 : break;
1352 24 : default:
1353 24 : harmonicFret = 12;
1354 24 : break;
1355 : }
1356 :
1357 25 : int overtoneFret = utils::harmonicOvertone(note, harmonicFret, type);
1358 25 : harmonicNote->setString(note->string());
1359 25 : harmonicNote->setFret(note->fret());
1360 25 : harmonicNote->setHarmonicFret(harmonicFret + fret);
1361 :
1362 25 : int pitch = staff->part()->instrument()->stringData()->getPitch(note->string(), overtoneFret, staff, note->tick());
1363 :
1364 25 : harmonicNote->setPitch(clampPitch(pitch));
1365 25 : harmonicNote->setTpcFromPitch(Prefer::SHARPS);
1366 25 : note->setHarmonicPitchOffset(harmonicNote->pitch() - note->pitch());
1367 25 : note->chord()->add(harmonicNote);
1368 :
1369 25 : switch (type) {
1370 19 : case HARMONIC_MARK_ARTIFICIAL:
1371 19 : result.harmonicArtificial = true;
1372 19 : break;
1373 0 : case HARMONIC_MARK_PINCH:
1374 0 : result.harmonicPinch = true;
1375 0 : break;
1376 1 : case HARMONIC_MARK_TAP:
1377 1 : result.harmonicTap = true;
1378 1 : break;
1379 5 : case HARMONIC_MARK_SEMI:
1380 5 : result.harmonicSemi = true;
1381 5 : break;
1382 : }
1383 : }
1384 : }
1385 :
1386 89 : if (bendParent) {
1387 12 : createBend(bendParent, bendData);
1388 : }
1389 :
1390 89 : if (modMask2 & EFFECT_VIBRATO) {
1391 7 : result.vibrato = true;
1392 : }
1393 :
1394 89 : if (modMask2 & EFFECT_TRILL) {
1395 0 : readUInt8(); // trill fret
1396 :
1397 0 : int period = readUInt8(); // trill length
1398 0 : result.trill = true;
1399 :
1400 0 : switch (period) {
1401 0 : case 1: // 16
1402 0 : break;
1403 0 : case 2: // 32
1404 0 : break;
1405 0 : case 3: // 64
1406 0 : break;
1407 0 : default:
1408 0 : LOGD("unknown trill period %d", period);
1409 0 : break;
1410 : }
1411 : }
1412 89 : return result;
1413 89 : }
1414 :
1415 : //---------------------------------------------------------
1416 : // readNote
1417 : //---------------------------------------------------------
1418 :
1419 639 : GuitarPro::ReadNoteResult GuitarPro5::readNote(int string, Note* note)
1420 : {
1421 639 : uint8_t noteBits = readUInt8();
1422 : //
1423 : // noteBits:
1424 : // 7 - Right hand or left hand fingering;
1425 : // 6 - Accentuated note
1426 : // 5 - Note type (rest, empty note, normal note);
1427 : // 4 - note dynamic;
1428 : // 3 - Presence of effects linked to the note;
1429 : // 2 - Ghost note;
1430 : // 1 - Dotted note; ?
1431 : // 0 - Time-independent duration
1432 :
1433 639 : if (noteBits & NOTE_GHOST) {
1434 0 : note->setGhost(true);
1435 : }
1436 :
1437 639 : bool tieNote = false;
1438 :
1439 639 : if (noteBits & NOTE_DEAD) {
1440 639 : uint8_t noteType = readUInt8();
1441 639 : if (noteType == 1) {
1442 : } //standard note
1443 28 : else if (noteType == 2) {
1444 21 : tieNote = true;
1445 7 : } else if (noteType == 3) { // dead notes
1446 7 : note->setHeadGroup(NoteHeadGroup::HEAD_CROSS);
1447 7 : note->setDeadNote(true);
1448 : } else {
1449 0 : LOGD("unknown note type: %d", noteType);
1450 : }
1451 : }
1452 :
1453 639 : int& previousDynamic = previousDynamicByTrack[note->track()];
1454 :
1455 639 : if (noteBits & NOTE_DYNAMIC) { // velocity
1456 478 : int d = readChar();
1457 478 : if (previousDynamic != d) {
1458 51 : previousDynamic = d;
1459 51 : addDynamic(note, d);
1460 : }
1461 161 : } else if (previousDynamic != DEFAULT_DYNAMIC) {
1462 19 : previousDynamic = DEFAULT_DYNAMIC;
1463 19 : addDynamic(note, previousDynamic);
1464 : }
1465 :
1466 639 : int fretNumber = 0;
1467 639 : if (noteBits & NOTE_FRET) {
1468 639 : fretNumber = readChar();
1469 : }
1470 :
1471 639 : if (noteBits & NOTE_FINGERING) {
1472 10 : int leftFinger = readUInt8();
1473 10 : int rightFinger = readUInt8();
1474 10 : Fingering* fi = Factory::createFingering(note);
1475 10 : String finger;
1476 : // if there is a valid left hand fingering
1477 10 : if (leftFinger < 5) {
1478 5 : if (leftFinger == 0) {
1479 1 : finger = u"T";
1480 4 : } else if (leftFinger == 1) {
1481 1 : finger = u"1";
1482 3 : } else if (leftFinger == 2) {
1483 1 : finger = u"2";
1484 2 : } else if (leftFinger == 3) {
1485 1 : finger = u"3";
1486 1 : } else if (leftFinger == 4) {
1487 1 : finger = u"4";
1488 : }
1489 : } else {
1490 5 : if (rightFinger == 0) {
1491 1 : finger = u"T";
1492 4 : } else if (rightFinger == 1) {
1493 1 : finger = u"I";
1494 3 : } else if (rightFinger == 2) {
1495 1 : finger = u"M";
1496 2 : } else if (rightFinger == 3) {
1497 1 : finger = u"A";
1498 1 : } else if (rightFinger == 4) {
1499 1 : finger = u"O";
1500 : }
1501 : }
1502 10 : fi->setPlainText(finger);
1503 10 : note->add(fi);
1504 10 : fi->reset();
1505 10 : }
1506 :
1507 639 : if (noteBits & 0x1) { // Time independent duration
1508 0 : skip(8);
1509 : }
1510 :
1511 : // check if a note is supposed to be accented, and give it the marcato type
1512 639 : if (noteBits & NOTE_MARCATO) {
1513 1 : Articulation* art = Factory::createArticulation(note->score()->dummy());
1514 1 : art->setSymId(SymId::articMarcatoAbove);
1515 1 : if (!EditChord::toggleArticulation(note->score(), note, art)) {
1516 0 : delete art;
1517 : }
1518 : }
1519 : // check if a note is supposed to be accented, and give it the sforzato type
1520 638 : else if (noteBits & NOTE_SFORZATO) {
1521 0 : Articulation* art = Factory::createArticulation(note->score()->dummy());
1522 0 : art->setSymId(SymId::articAccentAbove);
1523 0 : note->add(art);
1524 0 : if (!EditChord::toggleArticulation(note->score(), note, art)) {
1525 0 : delete art;
1526 : }
1527 : }
1528 :
1529 639 : readUInt8(); //skip
1530 :
1531 639 : Staff* staff = note->staff();
1532 639 : if (fretNumber == 255 || fretNumber < 0) {
1533 0 : fretNumber = 0;
1534 0 : note->setHeadGroup(NoteHeadGroup::HEAD_CROSS);
1535 0 : note->setDeadNote(true);
1536 : }
1537 639 : int pitch = staff->part()->instrument()->stringData()->getPitch(string, fretNumber, staff, note->tick());
1538 639 : note->setFret(fretNumber);
1539 639 : note->setString(string);
1540 639 : note->setPitch(pitch);
1541 :
1542 : // This function uses string and fret number, so it should be set before this
1543 639 : ReadNoteResult result;
1544 639 : if (noteBits & NOTE_SLUR) {
1545 89 : result = readNoteEffects(note);
1546 : }
1547 :
1548 639 : if (tieNote) {
1549 21 : auto staffIdx = note->staffIdx();
1550 21 : if (dead_end[{ static_cast<int>(staffIdx), string }]) {
1551 0 : note->setFret(INVALID_FRET_INDEX);
1552 0 : result.slur = false;
1553 0 : return result;
1554 : }
1555 21 : if (slurs[staffIdx]) {
1556 1 : score->removeSpanner(slurs[staffIdx]);
1557 1 : delete slurs[staffIdx];
1558 1 : slurs[staffIdx] = 0;
1559 : }
1560 21 : bool found = false;
1561 21 : Chord* chord = note->chord();
1562 21 : Segment* segment = chord->segment()->prev1(SegmentType::ChordRest);
1563 21 : track_idx_t track = note->track();
1564 21 : std::vector<ChordRest*> chords;
1565 21 : Note* true_note = nullptr;
1566 25 : while (segment) {
1567 25 : EngravingItem* e = segment->element(track);
1568 25 : if (e && e->isChord()) {
1569 23 : Chord* chord2 = toChord(e);
1570 38 : for (Note* note2 : chord2->notes()) {
1571 36 : if (note2->string() == string) {
1572 21 : if (chords.empty()) {
1573 19 : Tie* tie = Factory::createTie(note2);
1574 19 : tie->setEndNote(note);
1575 19 : note2->add(tie);
1576 : }
1577 :
1578 : // fixing gp5 bug with not storying let ring for tied notes
1579 21 : if (m_letRingForChords.find(chord2) != m_letRingForChords.end()) {
1580 2 : result.letRing = true;
1581 2 : muse::remove(m_letRingForChords, chord2);
1582 : }
1583 :
1584 21 : if (m_harmonicNotes.find(note) != m_harmonicNotes.end() && m_harmonicNotes.find(note2) != m_harmonicNotes.end()) {
1585 12 : Note* startHarmonicNote = m_harmonicNotes.at(note2);
1586 12 : Note* endHarmonicNote = m_harmonicNotes.at(note);
1587 :
1588 12 : Tie* tieHarmonic = Factory::createTie(startHarmonicNote);
1589 12 : tieHarmonic->setEndNote(endHarmonicNote);
1590 12 : startHarmonicNote->add(tieHarmonic);
1591 :
1592 12 : muse::remove(m_harmonicNotes, startHarmonicNote);
1593 12 : muse::remove(m_harmonicNotes, endHarmonicNote);
1594 : }
1595 :
1596 21 : note->setFret(note2->fret());
1597 21 : note->setPitch(note2->pitch());
1598 21 : true_note = note2;
1599 21 : if (m_tremolosInChords.find(chord2) != m_tremolosInChords.end()) {
1600 0 : TremoloType type = m_tremolosInChords.at(chord2);
1601 0 : DO_ASSERT(!isTremoloTwoChord(type));
1602 0 : TremoloSingleChord* t = Factory::createTremoloSingleChord(chord);
1603 0 : t->setTremoloType(type);
1604 0 : chord->add(t);
1605 0 : muse::remove(m_tremolosInChords, chord2);
1606 0 : m_tremolosInChords[chord] = type;
1607 : }
1608 :
1609 21 : found = true;
1610 21 : break;
1611 : }
1612 : }
1613 23 : if (found) {
1614 21 : break;
1615 2 : } else if (e) {
1616 2 : chords.push_back(toChordRest(e));
1617 : }
1618 : }
1619 4 : segment = segment->prev1(SegmentType::ChordRest);
1620 : }
1621 :
1622 21 : if (true_note && !chords.empty()) {
1623 2 : Note* end_note = note;
1624 4 : for (unsigned int i = 0; i < chords.size(); ++i) {
1625 2 : Chord* chord1 = nullptr;
1626 2 : ChordRest* cr = chords.at(i);
1627 2 : if (cr->isChord()) {
1628 2 : chord1 = toChord(cr);
1629 : } else {
1630 0 : Rest* rest = toRest(cr);
1631 0 : Fraction dur = rest->ticks();
1632 0 : TDuration dut = rest->durationType();
1633 0 : Segment* seg = rest->segment();
1634 0 : seg->remove(rest);
1635 0 : Tuplet* tuplet = rest->tuplet();
1636 0 : if (tuplet) {
1637 0 : tuplet->remove(rest);
1638 : }
1639 0 : delete rest;
1640 0 : chord1 = Factory::createChord(seg);
1641 0 : chord1->setTrack(note->track());
1642 0 : chord1->setTicks(dur);
1643 0 : chord1->setDurationType(dut);
1644 0 : seg->add(chord1);
1645 0 : if (tuplet) {
1646 0 : tuplet->add(chord1);
1647 : }
1648 : }
1649 :
1650 2 : Note* note2 = Factory::createNote(chord1);
1651 2 : note2->setString(true_note->string());
1652 2 : note2->setFret(true_note->fret());
1653 2 : note2->setPitch(true_note->pitch());
1654 2 : note2->setTpcFromPitch(Prefer::SHARPS);
1655 2 : chord1->setNoteType(true_note->noteType());
1656 2 : chord1->add(note2);
1657 2 : Tie* tie = Factory::createTie(note2);
1658 2 : tie->setEndNote(end_note);
1659 2 : end_note->setHarmonic(true_note->harmonic());
1660 2 : end_note = note2;
1661 2 : note2->add(tie);
1662 : }
1663 2 : Tie* tie = Factory::createTie(true_note);
1664 2 : tie->setEndNote(end_note);
1665 2 : end_note->setHarmonic(true_note->harmonic());
1666 2 : true_note->add(tie);
1667 : }
1668 21 : if (!found) {
1669 0 : note->setFret(INVALID_FRET_INDEX);
1670 0 : dead_end[{ static_cast<int>(staffIdx), string }] = true;
1671 0 : LOGD("tied note not found, pitch %d fret %d string %d", note->pitch(), note->fret(), note->string());
1672 0 : result.slur = false;
1673 0 : return result;
1674 : }
1675 21 : }
1676 639 : dead_end[{ static_cast<int>(note->staffIdx()), string }] = false;
1677 639 : return result;
1678 : }
1679 :
1680 0 : float GuitarPro5::naturalHarmonicFromFret(int fret)
1681 : {
1682 0 : switch (fret) {
1683 0 : case 2:
1684 0 : return 2.4f;
1685 0 : case 3:
1686 0 : return 3.2f;
1687 0 : case 4:
1688 : case 5:
1689 : case 7:
1690 : case 9:
1691 : case 12:
1692 : case 16:
1693 : case 17:
1694 : case 19:
1695 : case 24:
1696 0 : return fret;
1697 0 : case 8:
1698 0 : return 8.2f;
1699 0 : case 10:
1700 0 : return 9.6f;
1701 0 : case 14:
1702 0 : return 14.7f;
1703 0 : case 15:
1704 0 : return 14.7f;
1705 0 : case 21:
1706 0 : return 21.7f;
1707 0 : case 22:
1708 0 : return 21.7f;
1709 0 : default:
1710 0 : return 12.0f;
1711 : }
1712 : }
1713 :
1714 40 : void GuitarPro5::addGlissandos()
1715 : {
1716 43 : for (auto& [startNote, endNote] : m_glissandoNotePairs) {
1717 3 : Note* currentStart = startNote;
1718 3 : if (startNote->bendFor()) {
1719 1 : Note* bendNote = startNote;
1720 1 : GuitarBend* bend = bendNote->bendFor();
1721 :
1722 2 : while (bend) {
1723 1 : bendNote = bend->endNote();
1724 1 : IF_ASSERT_FAILED(bendNote) {
1725 0 : LOGE() << "glissando start note may be incorrect";
1726 0 : break;
1727 : }
1728 :
1729 1 : if (!bendNote->chord()->isGraceAfter()) {
1730 0 : break;
1731 : }
1732 :
1733 1 : currentStart = bendNote;
1734 1 : bend = bendNote->bendFor();
1735 : }
1736 : }
1737 :
1738 3 : Glissando* gliss = mu::engraving::Factory::createGlissando(currentStart);
1739 3 : gliss->setStartElement(currentStart);
1740 3 : gliss->setTick(currentStart->tick());
1741 3 : gliss->setTrack(currentStart->track());
1742 3 : gliss->setGlissandoType(GlissandoType::STRAIGHT);
1743 3 : gliss->setGlissandoShift(true);
1744 3 : gliss->setEndElement(endNote);
1745 3 : gliss->setTick2(endNote->tick());
1746 3 : gliss->setTrack2(endNote->track());
1747 3 : score->addElement(gliss);
1748 :
1749 3 : std::vector<std::pair<Slur*, Note*> > movedSlurs;
1750 3 : for (Spanner* spanner : startNote->chord()->startingSpanners()) {
1751 2 : if (spanner && spanner->isSlur()) {
1752 2 : Slur* slur = toSlur(spanner);
1753 2 : if (slur->endElement() == endNote->chord()) {
1754 2 : gliss->setGlissandoShift(false);
1755 2 : slur->setConnectedElement(mu::engraving::Slur::ConnectedElement::GLISSANDO);
1756 2 : movedSlurs.push_back({ slur, currentStart });
1757 2 : break;
1758 : }
1759 : }
1760 : }
1761 :
1762 5 : for (auto& [slur, note] : movedSlurs) {
1763 2 : slur->setStartElement(note->chord());
1764 2 : slur->setTick(note->tick());
1765 2 : slur->setTrack(note->track());
1766 : }
1767 3 : }
1768 40 : }
1769 : } // namespace mu::iex::guitarpro
|