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 : #include "utils.h"
25 :
26 : #include "engraving/dom/arpeggio.h"
27 : #include "engraving/dom/articulation.h"
28 : #include "engraving/dom/chord.h"
29 : #include "engraving/dom/chordline.h"
30 : #include "engraving/dom/clef.h"
31 : #include "engraving/dom/factory.h"
32 : #include "engraving/dom/fingering.h"
33 : #include "engraving/dom/glissando.h"
34 : #include "engraving/dom/instrtemplate.h"
35 : #include "engraving/dom/lyrics.h"
36 : #include "engraving/dom/masterscore.h"
37 : #include "engraving/dom/measure.h"
38 : #include "engraving/dom/measurebase.h"
39 : #include "engraving/dom/note.h"
40 : #include "engraving/dom/notedot.h"
41 : #include "engraving/dom/part.h"
42 : #include "engraving/dom/rehearsalmark.h"
43 : #include "engraving/dom/rest.h"
44 : #include "engraving/dom/segment.h"
45 : #include "engraving/dom/slur.h"
46 : #include "engraving/dom/staff.h"
47 : #include "engraving/dom/stafftext.h"
48 : #include "engraving/dom/stafftype.h"
49 : #include "engraving/dom/stringdata.h"
50 : #include "engraving/dom/tempotext.h"
51 : #include "engraving/dom/tie.h"
52 : #include "engraving/dom/tremolosinglechord.h"
53 : #include "engraving/dom/tuplet.h"
54 : #include "engraving/dom/stringtunings.h"
55 : #include "engraving/dom/capo.h"
56 : #include "engraving/types/symid.h"
57 :
58 : #include "engraving/editing/editchord.h"
59 :
60 : #include "guitarprodrumset.h"
61 :
62 : #include "log.h"
63 :
64 : using namespace muse::io;
65 : using namespace mu::engraving;
66 :
67 : namespace mu::iex::guitarpro {
68 : //---------------------------------------------------------
69 : // readMixChange
70 : //---------------------------------------------------------
71 :
72 1 : bool GuitarPro4::readMixChange(Measure* measure)
73 : {
74 : /*char patch =*/
75 1 : readChar();
76 1 : signed char volume = readChar();
77 1 : signed char pan = readChar();
78 1 : signed char chorus = readChar();
79 1 : signed char reverb = readChar();
80 1 : signed char phase = readChar();
81 1 : signed char tremolo = readChar();
82 1 : int temp = readInt();
83 :
84 1 : bool tempoEdited = false;
85 :
86 1 : if (volume >= 0) {
87 0 : readChar();
88 : }
89 1 : if (pan >= 0) {
90 0 : readChar();
91 : }
92 1 : if (chorus >= 0) {
93 0 : readChar();
94 : }
95 1 : if (reverb >= 0) {
96 0 : readChar();
97 : }
98 1 : if (phase >= 0) {
99 0 : readChar();
100 : }
101 1 : if (tremolo >= 0) {
102 0 : readChar();
103 : }
104 1 : if (temp >= 0) {
105 1 : if (temp != previousTempo) {
106 1 : if (last_segment && last_segment->tick() != measure->tick()) {
107 0 : bool hasTempoText = false;
108 0 : for (EngravingItem* e : last_segment->annotations()) {
109 0 : hasTempoText |= e->isTempoText();
110 : }
111 0 : if (!hasTempoText) {
112 0 : TempoText* tt = Factory::createTempoText(last_segment);
113 0 : tt->setTempo(double(temp) / 60.0f);
114 0 : tt->setVisible(false);
115 0 : tt->setTrack(0);
116 0 : last_segment->add(tt);
117 : }
118 : }
119 1 : previousTempo = temp;
120 1 : setTempo(temp, measure);
121 : }
122 1 : last_segment = nullptr;
123 1 : readChar();
124 1 : tempoEdited = true;
125 : }
126 :
127 1 : readChar(); // bitmask: what should be applied to all tracks
128 1 : return tempoEdited;
129 : }
130 :
131 : //---------------------------------------------------------
132 : // readBeatEffects
133 : //---------------------------------------------------------
134 :
135 5 : int GuitarPro4::readBeatEffects(int track, Segment* segment)
136 : {
137 5 : int effects = 0;
138 5 : uint8_t fxBits1 = readUInt8();
139 5 : uint8_t fxBits2 = readUInt8();
140 5 : if (fxBits1 & BEAT_FADE) {
141 1 : effects = 4; // fade in
142 : }
143 5 : if (fxBits1 & BEAT_EFFECT) {
144 0 : effects = readUInt8(); // effect 1-tapping, 2-slapping, 3-popping
145 : }
146 5 : if (fxBits2 & BEAT_TREMOLO) {
147 0 : readTremoloBar(track, segment);
148 : }
149 5 : if (fxBits1 & BEAT_ARPEGGIO) {
150 2 : int strokeup = readUInt8(); // up stroke length
151 2 : int strokedown = readUInt8(); // down stroke length
152 :
153 2 : Arpeggio* a = Factory::createArpeggio(score->dummy());
154 2 : if (strokeup > 0) {
155 1 : a->setArpeggioType(ArpeggioType::UP_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::DOWN_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 :
169 2 : if (a) {
170 2 : ChordRest* cr = Factory::createChord(segment);
171 2 : cr->setTrack(track);
172 2 : cr->add(a);
173 2 : segment->add(cr);
174 : }
175 : }
176 5 : if (fxBits2 & BEAT_STROKE_DIR) {
177 2 : effects = readUInt8(); // stroke pick direction
178 2 : effects += 4; //1 or 2 for effects becomes 4 or 5
179 : }
180 5 : if (fxBits1 & 0x01) { // GP3 column-wide vibrato
181 : }
182 5 : if (fxBits1 & 0x2) { // GP3 column-wide wide vibrato (="tremolo" in GP3)
183 : }
184 5 : return effects;
185 : }
186 :
187 : //---------------------------------------------------------
188 : // readNote
189 : //---------------------------------------------------------
190 :
191 346 : GuitarPro::ReadNoteResult GuitarPro4::readNote(int string, int staffIdx, Note* note)
192 : {
193 346 : uint8_t noteBits = readUInt8();
194 :
195 : //
196 : // noteBits:
197 : // 80 - Right hand or left hand fingering;
198 : // 40 - Accentuated note
199 : // 20 - Note type (rest, empty note, normal note);
200 : // 10 - note dynamic;
201 : // 8 - Presence of effects linked to the note;
202 : // 4 - Ghost note;
203 : // 2 - Dotted note; ?
204 : // 1 - Time-independent duration
205 :
206 346 : if (noteBits & BEAT_TREMOLO) {
207 : //note->setHeadGroup(NoteHeadGroup::HEAD_CROSS);
208 0 : note->setGhost(true);
209 : }
210 :
211 346 : bool tieNote = false;
212 346 : uint8_t variant = 1;
213 346 : if (noteBits & BEAT_EFFECT) { // 0x20
214 346 : variant = readUInt8();
215 346 : if (variant == 1) { // normal note
216 3 : } else if (variant == 2) {
217 : /* guitar pro 4 bundles tied notes with slides in the representation
218 : * we take note when we see ties and do not create slides for these notes. */
219 3 : slides[staffIdx * VOICES] = -2;
220 3 : tieNote = true;
221 0 : } else if (variant == 3) { // dead notes = ghost note
222 0 : note->setHeadGroup(NoteHeadGroup::HEAD_CROSS);
223 0 : note->setDeadNote(true);
224 : } else {
225 0 : LOGD("unknown note variant: %d", variant);
226 : }
227 : }
228 :
229 346 : if (noteBits & 0x1) { // note != beat
230 0 : int a = readUInt8(); // length
231 0 : int b = readUInt8(); // t
232 0 : LOGD(" Time independent note len, len %d t %d", a, b);
233 : }
234 346 : if (noteBits & 0x2) { // note is dotted
235 : //readUInt8();
236 : }
237 :
238 346 : int& previousDynamic = previousDynamicByTrack[note->track()];
239 :
240 : // set dynamic information on note if different from previous note
241 346 : if (noteBits & NOTE_DYNAMIC) { // 0x10
242 265 : int d = readChar();
243 265 : if (previousDynamic != d) {
244 27 : previousDynamic = d;
245 27 : addDynamic(note, d);
246 : }
247 81 : } else if (previousDynamic != DEFAULT_DYNAMIC) {
248 8 : previousDynamic = DEFAULT_DYNAMIC;
249 8 : addDynamic(note, previousDynamic);
250 : }
251 :
252 346 : int fretNumber = -1;
253 346 : if (noteBits & NOTE_FRET) { // 0x20
254 : // TODO: special case if note is tied
255 346 : fretNumber = readUInt8();
256 : }
257 :
258 : // check if a note is supposed to be accented, and give it the sforzato type
259 346 : if (noteBits & NOTE_SFORZATO) { // 0x40
260 3 : Articulation* art = Factory::createArticulation(note->score()->dummy());
261 3 : art->setSymId(SymId::articAccentAbove);
262 3 : if (!EditChord::toggleArticulation(note->score(), note, art)) {
263 0 : delete art;
264 : }
265 : }
266 :
267 346 : if (noteBits & NOTE_FINGERING) { // 0x80
268 10 : int leftFinger = readUInt8();
269 10 : int rightFinger = readUInt8();
270 10 : Fingering* fi = Factory::createFingering(note);
271 10 : String finger;
272 : // if there is a valid left hand fingering
273 10 : if (leftFinger < 5) {
274 5 : if (leftFinger == 0) {
275 1 : finger = u"T";
276 4 : } else if (leftFinger == 1) {
277 1 : finger = u"1";
278 3 : } else if (leftFinger == 2) {
279 1 : finger = u"2";
280 2 : } else if (leftFinger == 3) {
281 1 : finger = u"3";
282 1 : } else if (leftFinger == 4) {
283 1 : finger = u"4";
284 : }
285 : } else {
286 5 : if (rightFinger == 0) {
287 1 : finger = u"T";
288 4 : } else if (rightFinger == 1) {
289 1 : finger = u"I";
290 3 : } else if (rightFinger == 2) {
291 1 : finger = u"M";
292 2 : } else if (rightFinger == 3) {
293 1 : finger = u"A";
294 1 : } else if (rightFinger == 4) {
295 1 : finger = u"O";
296 : }
297 : }
298 10 : fi->setPlainText(finger);
299 10 : note->add(fi);
300 10 : fi->reset();
301 10 : }
302 :
303 346 : ReadNoteResult readResult;
304 346 : uint8_t modMask2 = 0;
305 346 : if (noteBits & BEAT_EFFECTS) {
306 28 : uint8_t modMask1 = readUInt8();
307 28 : modMask2 = readUInt8();
308 28 : if (modMask1 & EFFECT_BEND) {
309 5 : readBend(note);
310 : }
311 28 : if (modMask1 & EFFECT_HAMMER) {
312 1 : readResult.hammerOnPullOff = true;
313 : }
314 28 : if (modMask1 & EFFECT_LET_RING) {
315 1 : readResult.letRing = true;
316 : }
317 28 : if (modMask2 & EFFECT_VIBRATO) {
318 0 : readResult.vibrato = true;
319 : }
320 28 : if (modMask1 & EFFECT_GRACE) {
321 0 : int fret = readUInt8(); // grace fret
322 0 : int dynamic = readUInt8(); // grace dynamic
323 0 : int transition = readUInt8(); // grace transition
324 0 : int duration = readUInt8(); // grace duration
325 :
326 0 : int grace_len = Constants::DIVISION / 8;
327 0 : if (duration == 1) {
328 0 : grace_len = Constants::DIVISION / 8; //32nd
329 0 : } else if (duration == 2) {
330 0 : grace_len = Constants::DIVISION / 6; //24th
331 0 : } else if (duration == 3) {
332 0 : grace_len = Constants::DIVISION / 4; //16th
333 : }
334 0 : Note* gn = Factory::createNote(score->dummy());
335 :
336 0 : if (fret == 255) {
337 0 : gn->setHeadGroup(NoteHeadGroup::HEAD_CROSS);
338 0 : gn->setGhost(true);
339 : }
340 0 : if (fret == 255) {
341 0 : fret = 0;
342 : }
343 0 : gn->setFret(fret);
344 0 : gn->setString(string);
345 0 : int grace_pitch = note->part()->instrument()->stringData()->getPitch(string, fret, note->staff(), note->tick());
346 0 : gn->setPitch(grace_pitch);
347 0 : gn->setTpcFromPitch();
348 :
349 0 : Chord* gc = Factory::createChord(score->dummy());
350 0 : gc->setTrack(note->chord()->track());
351 0 : gc->add(gn);
352 0 : gc->setOwnershipParent(note->chord());
353 :
354 0 : TDuration d;
355 0 : d.setVal(grace_len);
356 0 : if (grace_len == Constants::DIVISION / 6) {
357 0 : d.setDots(1);
358 : }
359 0 : gc->setDurationType(d);
360 0 : gc->setTicks(d.fraction());
361 0 : gc->setNoteType(NoteType::ACCIACCATURA);
362 0 : gc->mutldata()->setMag(note->chord()->staff()->staffMag(Fraction(0, 1)) * score->style().styleD(Sid::graceNoteMag));
363 0 : note->chord()->add(gc);
364 0 : addDynamic(gn, dynamic);
365 :
366 0 : if (transition == 0) {
367 : // no transition
368 0 : } else if (transition == 1) {
369 : //TODO: Add a 'slide' guitar effect when implemented
370 : //TODO-ws note->setSlideNote(gn);
371 0 : } else if (transition == 2 && fretNumber >= 0 && fretNumber <= 255 && fretNumber != gn->fret()) {
372 0 : } else if (transition == 3) {
373 : // TODO:
374 : // major: replace with a 'hammer-on' guitar effect when implemented
375 : // minor: make slurs for parts
376 :
377 0 : ChordRest* cr1 = toChord(gc);
378 0 : ChordRest* cr2 = toChord(note->chord());
379 :
380 0 : Slur* slur1 = Factory::createSlur(score->dummy());
381 0 : slur1->setStartElement(cr1);
382 0 : slur1->setEndElement(cr2);
383 0 : slur1->setTick(cr1->tick());
384 0 : slur1->setTick2(cr2->tick());
385 0 : slur1->setTrack(cr1->track());
386 0 : slur1->setTrack2(cr2->track());
387 : // this case specifies only two-note slurs, don't set a parent
388 0 : score->undoAddElement(slur1);
389 : }
390 : }
391 28 : if (modMask2 & EFFECT_STACCATO) { // staccato
392 0 : Chord* chord = note->chord();
393 0 : Articulation* a = Factory::createArticulation(chord);
394 0 : a->setSymId(SymId::articStaccatoAbove);
395 0 : chord->add(a);
396 : }
397 28 : if (modMask2 & EFFECT_PALM_MUTE) {
398 1 : readResult.palmMute = true;
399 : }
400 :
401 28 : if (modMask2 & EFFECT_TREMOLO) { // tremolo picking length
402 0 : int tremoloDivision = readUInt8();
403 0 : Chord* chord = note->chord();
404 0 : TremoloType type = TremoloType::INVALID_TREMOLO;
405 0 : if (tremoloDivision == 1) {
406 0 : type = TremoloType::R8;
407 0 : } else if (tremoloDivision == 2) {
408 0 : type = TremoloType::R16;
409 0 : } else if (tremoloDivision == 3) {
410 0 : type = TremoloType::R32;
411 : } else {
412 0 : LOGD("Unknown tremolo value");
413 : }
414 :
415 0 : if (type != TremoloType::INVALID_TREMOLO) {
416 0 : TremoloSingleChord* t = Factory::createTremoloSingleChord(chord);
417 0 : t->setTremoloType(type);
418 0 : chord->add(t);
419 : }
420 : }
421 28 : if (modMask2 & EFFECT_SLIDE) {
422 19 : int slideKind = readUInt8();
423 : // if slide >= 4 then we are not dealing with legato slide nor shift slide
424 19 : if (slideKind >= 3 || slideKind == 254 || slideKind == 255) {
425 16 : slide = slideKind;
426 : } else {
427 : //slides[note->chord()->track()] = slideKind;
428 3 : slideList.push_back(note);
429 : }
430 19 : if (slideKind == 2) {
431 1 : readResult.slur = true;
432 : }
433 : }
434 :
435 28 : if (modMask2 & EFFECT_TRILL) {
436 1 : readUInt8();
437 1 : /*int period =*/ readUInt8(); // trill length
438 1 : readResult.trill = true;
439 : }
440 : }
441 346 : if (fretNumber == -1) {
442 0 : LOGD("Note: no fret number, tie %d", tieNote);
443 : }
444 346 : Staff* staff = note->staff();
445 346 : if (fretNumber == 255) {
446 0 : fretNumber = 0;
447 0 : note->setHeadGroup(NoteHeadGroup::HEAD_CROSS);
448 0 : note->setGhost(true);
449 : }
450 : // dead note represented as high numbers - fix to zero
451 346 : if (fretNumber > 99 || fretNumber == -1) {
452 0 : fretNumber = 0;
453 : }
454 346 : int pitch = staff->part()->instrument()->stringData()->getPitch(string, fretNumber, staff, note->tick());
455 346 : note->setFret(fretNumber);
456 346 : note->setString(string);
457 346 : note->setPitch(std::min(pitch, mu::engraving::MAX_PITCH));
458 :
459 346 : if (modMask2 & 0x10) {
460 0 : int type = readUInt8(); // harmonic kind
461 0 : if (type == 1) { //Natural
462 0 : note->setHarmonic(false);
463 0 : } else if (type == 3) { // Tapped
464 0 : readResult.harmonicTap = true;
465 0 : } else if (type == 4) { //Pinch
466 0 : readResult.harmonicPinch = true;
467 0 : } else if (type == 5) { //semi
468 0 : readResult.harmonicSemi = true;
469 : } else { //Artificial
470 0 : readResult.harmonicArtificial = true;
471 0 : int harmonicFret = note->fret();
472 0 : harmonicFret += type - 10;
473 0 : Note* harmonicNote = Factory::createNote(note->chord());
474 0 : note->chord()->add(harmonicNote);
475 0 : harmonicNote->setFret(harmonicFret);
476 0 : harmonicNote->setString(note->string());
477 0 : harmonicNote->setPitch(note->staff()->part()->instrument()->stringData()->getPitch(note->string(), harmonicFret, note->staff(),
478 0 : note->tick()));
479 0 : harmonicNote->setTpcFromPitch();
480 : }
481 : }
482 :
483 346 : if (tieNote) {
484 3 : staff_idx_t si = note->staffIdx();
485 3 : if (slurs[si]) {
486 0 : score->removeSpanner(slurs[si]);
487 0 : delete slurs[si];
488 0 : slurs[si] = 0;
489 : }
490 3 : bool found = false;
491 3 : Chord* chord = note->chord();
492 3 : Segment* segment = chord->segment()->prev1(SegmentType::ChordRest);
493 3 : track_idx_t track = note->track();
494 3 : std::vector<ChordRest*> chords;
495 3 : Note* true_note = 0;
496 3 : while (segment) {
497 3 : EngravingItem* e = segment->element(track);
498 3 : if (e) {
499 3 : if (e->isChord()) {
500 3 : Chord* chord2 = toChord(e);
501 3 : for (Note* note2 : chord2->notes()) {
502 3 : if (note2->string() == string) {
503 3 : if (chords.empty()) {
504 3 : Tie* tie = Factory::createTie(note2);
505 3 : tie->setEndNote(note);
506 3 : note2->add(tie);
507 : }
508 3 : note->setFret(note2->fret());
509 3 : note->setPitch(note2->pitch());
510 3 : true_note = note2;
511 3 : found = true;
512 3 : break;
513 : }
514 : }
515 : }
516 3 : if (found) {
517 3 : break;
518 0 : } else if (e) {
519 0 : chords.push_back(toChordRest(e));
520 : }
521 : }
522 0 : segment = segment->prev1(SegmentType::ChordRest);
523 : }
524 3 : if (true_note && chords.size()) {
525 0 : Note* end_note = note;
526 0 : for (unsigned int i = 0; i < chords.size(); ++i) {
527 0 : Chord* chord1 = nullptr;
528 0 : auto cr = chords.at(i);
529 0 : if (cr->isChord()) {
530 0 : chord1 = toChord(cr);
531 : } else {
532 0 : Rest* rest = toRest(cr);
533 0 : auto dur = rest->ticks();
534 0 : auto dut = rest->durationType();
535 0 : auto seg = rest->segment();
536 0 : seg->remove(rest);
537 0 : auto tuplet = rest->tuplet();
538 0 : if (tuplet) {
539 0 : tuplet->remove(rest);
540 : }
541 0 : delete rest;
542 0 : chord1 = Factory::createChord(seg);
543 0 : chord1->setTrack(note->track());
544 0 : chord1->setTicks(dur);
545 0 : chord1->setDurationType(dut);
546 0 : seg->add(chord1);
547 0 : if (tuplet) {
548 0 : tuplet->add(chord1);
549 : }
550 : }
551 :
552 0 : Note* note2 = Factory::createNote(chord1);
553 0 : note2->setString(true_note->string());
554 0 : note2->setFret(true_note->fret());
555 0 : note2->setPitch(true_note->pitch());
556 0 : note2->setTpcFromPitch();
557 0 : chord1->setNoteType(true_note->noteType());
558 0 : chord1->add(note2);
559 0 : Tie* tie = Factory::createTie(note2);
560 0 : tie->setEndNote(end_note);
561 0 : end_note->setHarmonic(true_note->harmonic());
562 0 : end_note = note2;
563 0 : note2->add(tie);
564 : }
565 0 : Tie* tie = Factory::createTie(true_note);
566 0 : tie->setEndNote(end_note);
567 0 : end_note->setHarmonic(true_note->harmonic());
568 0 : true_note->add(tie);
569 : }
570 3 : if (!found) {
571 0 : LOGD("tied note not found, pitch %d fret %d string %d", note->pitch(), note->fret(), note->string());
572 0 : readResult.slur = false;
573 0 : return readResult;
574 : }
575 3 : }
576 :
577 346 : return readResult;
578 : }
579 :
580 : //---------------------------------------------------------
581 : // readInfo
582 : //---------------------------------------------------------
583 :
584 27 : void GuitarPro4::readInfo()
585 : {
586 27 : title = readDelphiString();
587 27 : subtitle = readDelphiString();
588 27 : artist = readDelphiString();
589 27 : album = readDelphiString();
590 27 : composer = readDelphiString();
591 27 : String copyright = readDelphiString();
592 27 : if (!copyright.isEmpty()) {
593 1 : score->setMetaTag(u"copyright", copyright);
594 : }
595 :
596 27 : readDelphiString(); // transcriber
597 27 : readDelphiString(); // instructions
598 27 : int n = readInt();
599 37 : for (int i = 0; i < n; ++i) {
600 10 : comments.append(readDelphiString());
601 : }
602 27 : }
603 :
604 : //---------------------------------------------------------
605 : // convertGP4SlideNum
606 : //---------------------------------------------------------
607 :
608 32 : int GuitarPro4::convertGP4SlideNum(int sl)
609 : {
610 32 : switch (sl) {
611 0 : case 1:
612 0 : return SHIFT_SLIDE;
613 0 : case 2:
614 0 : return LEGATO_SLIDE;
615 8 : case 3: // slide out downwards
616 8 : return SLIDE_OUT_DOWN;
617 8 : case 4: // slide out upwards
618 8 : return SLIDE_OUT_UP;
619 8 : case 254: // slide in from above
620 8 : return SLIDE_IN_ABOVE;
621 8 : case 255: // slide in from below
622 8 : return SLIDE_IN_BELOW;
623 : }
624 0 : return sl;
625 : }
626 :
627 : //---------------------------------------------------------
628 : // read
629 : //---------------------------------------------------------
630 :
631 27 : bool GuitarPro4::read(IODevice* io)
632 : {
633 27 : m_continiousElementsBuilder = std::make_unique<ContiniousElementsBuilder>(score);
634 27 : m_guitarBendImporter = std::make_unique<GuitarBendImporter>(score);
635 :
636 27 : f = io;
637 27 : curPos = 30;
638 :
639 27 : readInfo();
640 27 : readUInt8(); // triplet feeling
641 27 : readLyrics();
642 :
643 27 : int temp = readInt();
644 27 : key = readInt();
645 27 : /*int octave =*/ readUInt8(); // octave
646 :
647 27 : previousTempo = -1;
648 :
649 27 : readChannels();
650 27 : measures = readInt();
651 27 : staves = readInt();
652 :
653 27 : initDynamics(staves);
654 :
655 27 : curDynam.resize(staves * VOICES);
656 135 : for (auto& i : curDynam) {
657 108 : i = -1;
658 : }
659 :
660 27 : int tnumerator = 4;
661 27 : int tdenominator = 4;
662 109 : for (size_t i = 0; i < measures; ++i) {
663 82 : GpBar bar;
664 82 : uint8_t barBits = readUInt8();
665 82 : if (barBits & SCORE_TIMESIG_NUMERATOR) {
666 27 : tnumerator = readUInt8();
667 : }
668 82 : if (barBits & SCORE_TIMESIG_DENOMINATOR) {
669 27 : tdenominator = readUInt8();
670 : }
671 82 : if (barBits & SCORE_REPEAT_START) {
672 1 : bar.repeatFlags = bar.repeatFlags | mu::engraving::Repeat::START;
673 : }
674 82 : if (barBits & SCORE_REPEAT_END) { // number of repeats
675 2 : bar.repeatFlags = bar.repeatFlags | mu::engraving::Repeat::END;
676 2 : bar.repeats = readUInt8() + 1;
677 : }
678 82 : if (barBits & SCORE_VOLTA) { // a volta
679 7 : uint8_t voltaNumber = readUInt8();
680 25 : while (voltaNumber > 0) {
681 : // volta information is represented as a binary number
682 18 : bar.volta.voltaType = GP_VOLTA_BINARY;
683 18 : bar.volta.voltaInfo.push_back(voltaNumber & 1);
684 18 : voltaNumber >>= 1;
685 : }
686 : }
687 82 : if (barBits & SCORE_MARKER) {
688 1 : bar.marker = readDelphiString(); // new section?
689 1 : /*int color = */ readInt(); // color?
690 : }
691 82 : if (barBits & SCORE_KEYSIG) {
692 48 : int currentKey = readUInt8();
693 : /* key signatures are specified as
694 : * 1# = 1, 2# = 2, ..., 7# = 7
695 : * 1b = 255, 2b = 254, ... 7b = 249 */
696 48 : bar.keysig = currentKey <= 7 ? currentKey : -256 + currentKey;
697 48 : readUInt8(); // specifies major/minor mode
698 : }
699 82 : if (barBits & SCORE_DOUBLE_BAR) {
700 1 : bar.barLine = BarLineType::DOUBLE;
701 : }
702 82 : bar.timesig = Fraction(tnumerator, tdenominator);
703 82 : bars.push_back(bar);
704 82 : }
705 :
706 : //
707 : // create a part for every staff
708 : //
709 54 : for (size_t staffIdx = 0; staffIdx < staves; ++staffIdx) {
710 27 : Part* part = new Part(score);
711 27 : Staff* s = Factory::createStaff(part);
712 :
713 27 : score->appendStaff(s);
714 27 : score->appendPart(part);
715 : }
716 :
717 27 : createMeasures();
718 :
719 27 : setTempo(temp, score->firstMeasure());
720 :
721 53 : for (size_t i = 0; i < staves; ++i) {
722 : int tuning[GP_MAX_STRING_NUMBER];
723 :
724 27 : uint8_t c = readUInt8(); // simulations bitmask
725 27 : if (c & 0x2) { // 12 stringed guitar
726 : }
727 27 : if (c & 0x4) { // banjo track
728 : }
729 27 : String name = readPascalString(40);
730 27 : int strings = readInt();
731 27 : if (strings <= 0 || strings > GP_MAX_STRING_NUMBER) {
732 0 : return false;
733 : }
734 190 : for (int j = 0; j < strings; ++j) {
735 163 : tuning[j] = readInt();
736 : }
737 53 : for (int j = strings; j < GP_MAX_STRING_NUMBER; ++j) {
738 26 : readInt();
739 : }
740 27 : int midiPort = readInt() - 1;
741 27 : int midiChannel = readInt() - 1;
742 54 : if (midiChannel < 0 || midiChannel >= static_cast<int>(channelDefaults.size())) {
743 2 : LOGE() << "midiChannel " << midiChannel << " out of range 0-" << channelDefaults.size();
744 1 : return false;
745 : }
746 :
747 26 : /*int midiChannel2 =*/ readInt(); // - 1;
748 26 : int frets = readInt();
749 :
750 26 : int capo = readInt();
751 26 : /*int color =*/ readInt();
752 :
753 26 : std::vector<int> tuning2(strings);
754 : //int tuning2[strings];
755 183 : for (int k = 0; k < strings; ++k) {
756 157 : tuning2[strings - k - 1] = tuning[k];
757 : }
758 26 : bool useFlats = createTuningString(strings, &tuning2[0]);
759 26 : StringData stringData(frets, strings, &tuning2[0], useFlats);
760 26 : Part* part = score->staff(i)->part();
761 26 : Instrument* instr = part->instrument();
762 26 : instr->setStringData(stringData);
763 26 : instr->setSingleNoteDynamics(false);
764 26 : part->setPlainLongName(name);
765 :
766 26 : int patch = channelDefaults[midiChannel].patch;
767 :
768 : //
769 : // determine clef
770 : //
771 26 : Staff* staff = score->staff(i);
772 26 : ClefType clefId = ClefType::G;
773 26 : if (midiChannel == GP_DEFAULT_PERCUSSION_CHANNEL) {
774 0 : clefId = ClefType::PERC;
775 0 : StaffTypes type = StaffTypes::PERC_DEFAULT;
776 0 : if (auto it = drumset::PERC_STAFF_LINES_FROM_INSTRUMENT.find(name.toStdString());
777 0 : it != drumset::PERC_STAFF_LINES_FROM_INSTRUMENT.end()) {
778 0 : drumset::initGuitarProPercussionSet(it->second);
779 0 : drumset::setInstrumentDrumset(instr, it->second);
780 0 : switch (it->second.numLines) {
781 0 : case 1:
782 0 : type = StaffTypes::PERC_1LINE;
783 0 : break;
784 0 : case 2:
785 0 : type = StaffTypes::PERC_2LINE;
786 0 : break;
787 0 : case 3:
788 0 : type = StaffTypes::PERC_3LINE;
789 0 : break;
790 0 : default:
791 0 : type = StaffTypes::PERC_DEFAULT;
792 0 : break;
793 : }
794 : } else {
795 0 : drumset::initGuitarProDrumset();
796 0 : instr->setDrumset(drumset::gpDrumset);
797 : }
798 0 : staff->setStaffType(Fraction(0, 1), *StaffType::preset(type));
799 : } else {
800 26 : clefId = defaultClef(patch);
801 : }
802 :
803 26 : Measure* measure = score->firstMeasure();
804 26 : if (measure->tick() != Fraction(0, 1)) {
805 0 : Segment* segment = measure->getSegment(SegmentType::HeaderClef, Fraction(0, 1));
806 :
807 0 : Clef* clef = Factory::createClef(segment);
808 0 : clef->setClefType(clefId);
809 0 : clef->setTrack(i * VOICES);
810 0 : segment->add(clef);
811 : } else {
812 26 : staff->setDefaultClefType(ClefTypeList(clefId, clefId));
813 : }
814 :
815 26 : if (capo > 0 && !engravingConfiguration()->guitarProImportExperimental()) {
816 2 : Segment* s = measure->getSegment(SegmentType::ChordRest, measure->tick());
817 2 : const size_t track = i * VOICES;
818 :
819 2 : CapoParams params;
820 2 : params.active = true;
821 2 : params.transposeMode = CapoParams::TransposeMode::TAB_ONLY;
822 2 : params.fretPosition = capo;
823 :
824 2 : Capo* capoEl = Factory::createCapo(s);
825 2 : capoEl->setTrack(track);
826 2 : capoEl->setParams(params);
827 2 : s->add(capoEl);
828 :
829 2 : staff->insertCapoParams({ 0, 1 }, params, true);
830 2 : }
831 :
832 26 : InstrChannel* ch = instr->channel(0);
833 26 : if (midiChannel == GP_DEFAULT_PERCUSSION_CHANNEL) {
834 0 : ch->setProgram(0);
835 0 : ch->setBank(128);
836 : } else {
837 26 : ch->setProgram(patch);
838 26 : ch->setBank(0);
839 : }
840 26 : ch->setVolume(channelDefaults[midiChannel].volume);
841 26 : ch->setPan(channelDefaults[midiChannel].pan);
842 26 : ch->setChorus(channelDefaults[midiChannel].chorus);
843 26 : ch->setReverb(channelDefaults[midiChannel].reverb);
844 26 : staff->part()->setMidiChannel(midiChannel, midiPort);
845 : // missing: phase, tremolo
846 27 : }
847 :
848 26 : slurs.resize(staves, nullptr);
849 26 : tupleKind.resize(staves);
850 52 : for (auto& i : tupleKind) {
851 26 : i = 0;
852 : }
853 :
854 26 : Measure* measure = score->firstMeasure();
855 26 : bool mixChange = false;
856 26 : bool lastSlurAdd = false;
857 106 : for (size_t bar = 0; bar < measures; ++bar, measure = measure->nextMeasure()) {
858 80 : if (!f->isReadable()) {
859 0 : break;
860 : }
861 80 : const GpBar& gpbar = bars[bar];
862 80 : if (!gpbar.marker.isEmpty()) {
863 1 : Segment* segment = measure->getSegment(SegmentType::ChordRest, measure->tick());
864 1 : RehearsalMark* s = new RehearsalMark(segment);
865 1 : s->setPlainText(gpbar.marker.trimmed());
866 1 : s->setTrack(0);
867 1 : segment->add(s);
868 : }
869 :
870 80 : std::vector<Tuplet*> tuplets(staves);
871 160 : for (size_t staffIdx = 0; staffIdx < staves; ++staffIdx) {
872 80 : tuplets[staffIdx] = 0;
873 : }
874 :
875 160 : for (size_t staffIdx = 0; staffIdx < staves; ++staffIdx) {
876 80 : Fraction measureLen = { 0, 1 };
877 80 : Fraction tick = measure->tick();
878 80 : int beats = readInt();
879 80 : track_idx_t track = staffIdx * VOICES;
880 :
881 80 : if (!f->isReadable()) {
882 0 : break;
883 : }
884 374 : for (int beat = 0; beat < beats; ++beat) {
885 294 : slide = -1;
886 294 : if (muse::contains(slides, static_cast<int>(track))) {
887 268 : slide = muse::take(slides, static_cast<int>(track));
888 : }
889 :
890 294 : uint8_t beatBits = readUInt8();
891 294 : bool dotted = beatBits & 0x1;
892 294 : int pause = -1;
893 294 : if (beatBits & BEAT_PAUSE) {
894 35 : pause = readUInt8();
895 : }
896 294 : int len = readChar();
897 294 : int tuple = 0;
898 294 : if (beatBits & BEAT_TUPLET) {
899 4 : tuple = readInt();
900 : }
901 294 : Segment* segment = measure->getSegment(SegmentType::ChordRest, tick);
902 294 : if (beatBits & BEAT_CHORD) {
903 1 : size_t numStrings = score->staff(staffIdx)->part()->instrument()->stringData()->strings();
904 1 : int header = readUInt8();
905 1 : String name;
906 1 : if ((header & 1) == 0) {
907 0 : name = readDelphiString();
908 0 : readChord(segment, static_cast<int>(staffIdx * VOICES), static_cast<int>(numStrings), name, false);
909 : } else {
910 1 : skip(16);
911 1 : name = readPascalString(21);
912 1 : skip(4);
913 1 : readChord(segment, static_cast<int>(staffIdx * VOICES), static_cast<int>(numStrings), name, true);
914 1 : skip(32);
915 : }
916 1 : }
917 :
918 294 : Lyrics* lyrics = 0;
919 294 : if (beatBits & BEAT_LYRICS) {
920 0 : lyrics = Factory::createLyrics(score->dummy());
921 0 : auto str = readDelphiString();
922 : //TODO-ws str.erase(std::remove_if(str.begin(), str.end(), [](char c){return c == '_'; }), str.end());
923 0 : lyrics->setPlainText(str);
924 0 : }
925 294 : gpLyrics.beatCounter++;
926 294 : if (gpLyrics.beatCounter >= gpLyrics.fromBeat && static_cast<size_t>(gpLyrics.lyricTrack) == staffIdx + 1) {
927 0 : size_t index = gpLyrics.beatCounter - gpLyrics.fromBeat;
928 0 : if (index < gpLyrics.lyrics.size()) {
929 0 : lyrics = Factory::createLyrics(score->dummy());
930 0 : lyrics->setPlainText(gpLyrics.lyrics[index]);
931 : }
932 : }
933 294 : int beatEffects = 0;
934 294 : if (beatBits & BEAT_EFFECTS) {
935 5 : beatEffects = readBeatEffects(static_cast<int>(track), segment);
936 : }
937 294 : last_segment = segment;
938 294 : if (beatBits & BEAT_MIX_CHANGE) {
939 1 : readMixChange(measure);
940 1 : mixChange = true;
941 : }
942 294 : int strings = readUInt8(); // used strings mask
943 294 : Fraction l = len2fraction(len);
944 :
945 : // Some beat effects could add a Chord before this
946 294 : ChordRest* cr = segment->cr(track);
947 :
948 294 : if (strings == 0) {
949 35 : if (segment->cr(track)) {
950 0 : segment->remove(segment->cr(track));
951 0 : delete cr;
952 0 : cr = 0;
953 : }
954 35 : cr = Factory::createRest(segment);
955 : } else {
956 259 : if (!segment->cr(track)) {
957 257 : cr = Factory::createChord(segment);
958 : }
959 : }
960 294 : cr->setOwnershipParent(segment);
961 294 : cr->setTrack(track);
962 294 : if (lyrics) {
963 0 : cr->add(lyrics);
964 : }
965 :
966 294 : TDuration d(l);
967 294 : d.setDots(dotted ? 1 : 0);
968 :
969 294 : if (dotted) {
970 0 : l = l + (l * Fraction(1, 2));
971 : }
972 294 : if (tuple) {
973 4 : Tuplet* tuplet = tuplets[staffIdx];
974 4 : if ((tuplet == 0) || (tuplet->elementsDuration() == tuplet->baseLen().fraction() * tuplet->ratio().numerator())) {
975 1 : tuplet = Factory::createTuplet(measure);
976 1 : tuplet->setTick(tick);
977 1 : tuplet->setTrack(cr->track());
978 1 : tuplets[staffIdx] = tuplet;
979 1 : setTuplet(tuplet, tuple);
980 1 : tuplet->setOwnershipParent(measure);
981 : }
982 4 : tuplet->setTrack(track);
983 4 : tuplet->setBaseLen(l);
984 4 : tuplet->setTicks(l * tuplet->ratio().denominator());
985 4 : cr->setTuplet(tuplet);
986 4 : tuplet->add(cr);
987 : } else {
988 290 : tuplets[staffIdx] = 0; // needed?
989 : }
990 294 : cr->setTicks(l);
991 294 : if (cr->isRest() && (pause == 0 || l >= measure->ticks())) {
992 7 : cr->setDurationType(DurationType::V_MEASURE);
993 7 : cr->setTicks(measure->ticks());
994 : } else {
995 287 : cr->setDurationType(d);
996 : }
997 294 : if (!segment->cr(track)) {
998 292 : segment->add(cr);
999 : }
1000 294 : Staff* staff = cr->staff();
1001 294 : size_t numStrings = staff->part()->instrument()->stringData()->strings();
1002 294 : bool hasSlur = false;
1003 294 : bool hasHammerOnPullOff = false;
1004 294 : bool hasLetRing = false;
1005 294 : bool hasPalmMute = false;
1006 294 : bool hasTrill = false;
1007 294 : bool hasVibratoLeftHand = false;
1008 294 : bool hasVibratoWTremBar = false;
1009 294 : bool hasHarmonicArtificial = false;
1010 294 : bool hasHarmonicPinch = false;
1011 294 : bool hasHarmonicTap = false;
1012 294 : bool hasHarmonicSemi = false;
1013 :
1014 294 : int dynam = -1;
1015 294 : if (cr && cr->isChord()) {
1016 2072 : for (int i = 6; i >= 0; --i) {
1017 1813 : if (strings & (1 << i) && ((6 - i) < static_cast<int>(numStrings))) {
1018 346 : Note* note = Factory::createNote(toChord(cr));
1019 : // apply dotted notes to the note
1020 346 : if (dotted) {
1021 : // there is at most one dotted note in this guitar pro version
1022 0 : NoteDot* dot = Factory::createNoteDot(note);
1023 0 : dot->setTrack(track); // needed to know the staff it belongs to (and detect tablature)
1024 0 : dot->setVisible(true);
1025 0 : note->add(dot);
1026 : }
1027 346 : toChord(cr)->add(note);
1028 :
1029 346 : ReadNoteResult readResult = readNote(6 - i, static_cast<int>(staffIdx), note);
1030 346 : hasSlur = readResult.slur || hasSlur;
1031 346 : hasHammerOnPullOff = readResult.hammerOnPullOff || hasHammerOnPullOff;
1032 346 : hasLetRing = readResult.letRing || hasLetRing;
1033 346 : hasPalmMute = readResult.palmMute || hasPalmMute;
1034 346 : hasTrill = readResult.trill || hasTrill;
1035 346 : hasVibratoLeftHand = readResult.vibrato || hasVibratoLeftHand;
1036 346 : hasHarmonicArtificial = readResult.harmonicArtificial || hasHarmonicArtificial;
1037 346 : hasHarmonicPinch = readResult.harmonicPinch || hasHarmonicPinch;
1038 346 : hasHarmonicTap = readResult.harmonicTap || hasHarmonicTap;
1039 346 : hasHarmonicSemi = readResult.harmonicSemi || hasHarmonicSemi;
1040 346 : dynam = std::max(dynam, previousDynamicByTrack[track]);
1041 346 : note->setTpcFromPitch();
1042 : }
1043 : }
1044 :
1045 259 : bool hasVibratoLeftHandOnBeat = false;
1046 259 : bool hasVibratoWTremBarOnBeat = false;
1047 259 : applyBeatEffects(toChord(cr), beatEffects, hasVibratoLeftHandOnBeat, hasVibratoWTremBarOnBeat);
1048 259 : hasVibratoLeftHand = hasVibratoLeftHand || hasVibratoLeftHandOnBeat;
1049 259 : hasVibratoWTremBar = hasVibratoWTremBar || hasVibratoWTremBarOnBeat;
1050 259 : if (dynam != curDynam[track]) {
1051 35 : curDynam[track] = dynam;
1052 35 : addDynamic(toChord(cr)->notes().front(), dynam);
1053 : }
1054 : }
1055 :
1056 294 : if (cr) {
1057 294 : addLetRing(cr, hasLetRing);
1058 294 : addPalmMute(cr, hasPalmMute);
1059 294 : addTrill(cr, hasTrill);
1060 294 : addHammerOnPullOff(cr, hasHammerOnPullOff);
1061 294 : addVibratoLeftHand(cr, hasVibratoLeftHand);
1062 294 : addVibratoWTremBar(cr, hasVibratoWTremBar);
1063 294 : addHarmonicMarks(cr, hasHarmonicArtificial, hasHarmonicPinch, hasHarmonicTap, hasHarmonicSemi);
1064 : }
1065 :
1066 : // if we see that a tied note has been constructed do not create the tie
1067 294 : if (slides[static_cast<int>(track)] == -2) {
1068 3 : slide = 0;
1069 3 : slides[static_cast<int>(track)] = -1;
1070 : }
1071 294 : bool slurSwap = true;
1072 294 : if (slide != 2) {
1073 294 : if (hasSlur && (slurs[staffIdx] == 0)) {
1074 1 : Slur* slur = Factory::createSlur(score->dummy());
1075 1 : slur->setOwnershipParent(0);
1076 1 : slur->setTrack(track);
1077 1 : slur->setTrack2(track);
1078 1 : slur->setTick(cr->tick());
1079 1 : slur->setTick2(cr->tick());
1080 1 : slur->setStartElement(cr);
1081 1 : slurs[staffIdx] = slur;
1082 1 : score->addElement(slur);
1083 293 : } else if (slurs[staffIdx] && !hasSlur) {
1084 : // TODO: check slur
1085 1 : Slur* s = slurs[staffIdx];
1086 1 : slurs[staffIdx] = 0;
1087 1 : s->setTick2(cr->tick());
1088 1 : s->setTrack2(cr->track());
1089 1 : s->setEndElement(cr);
1090 1 : if (cr->isChord()) {
1091 1 : lastSlurAdd = true;
1092 1 : slurSwap = false;
1093 : }
1094 : //TODO-ws cr->has_slur = true;
1095 292 : } else if (slurs[staffIdx] && hasSlur) {
1096 : }
1097 : }
1098 294 : if (cr && (cr->isChord()) && slide > 0) {
1099 16 : auto chord = toChord(cr);
1100 16 : auto effect = convertGP4SlideNum(slide);
1101 16 : if (slide > 2) {
1102 16 : createSlide(convertGP4SlideNum(slide), cr, static_cast<int>(staffIdx));
1103 : }
1104 16 : if (slide < 3 || effect == SLIDE_OUT_UP) {
1105 4 : Note* last = chord->upNote();
1106 4 : auto seg = chord->segment();
1107 4 : Measure* mes = seg->measure();
1108 15 : while ((seg = seg->prev()) || (mes = mes->prevMeasure())) {
1109 12 : if (!seg) {
1110 0 : break; //seg = mes->last();
1111 : }
1112 12 : if (seg->segmentType() == SegmentType::ChordRest
1113 12 : && seg->cr(chord->track()) && seg->cr(chord->track())->isChord()) {
1114 6 : bool br = false;
1115 6 : Chord* cr1 = toChord(seg->cr(chord->track()));
1116 6 : if (cr1) {
1117 11 : for (auto n : cr1->notes()) {
1118 6 : if (n->string() == last->string()) {
1119 1 : Glissando* s = mu::engraving::Factory::createGlissando(n);
1120 1 : s->setStartElement(n);
1121 1 : s->setTick(seg->tick());
1122 1 : s->setTrack(chord->track());
1123 1 : s->setGlissandoType(GlissandoType::STRAIGHT);
1124 1 : s->setEndElement(last);
1125 1 : s->setTick2(chord->segment()->tick());
1126 1 : s->setTrack2(chord->track());
1127 1 : s->setGlissandoStyle(n->part()->instrument(n->tick())->glissandoStyle());
1128 1 : score->addElement(s);
1129 1 : if (slide == 2 || effect == SLIDE_OUT_UP) {
1130 1 : if (!lastSlurAdd) {
1131 1 : createSlur(true, chord->staffIdx(), cr1);
1132 1 : createSlur(false, chord->staffIdx(), chord);
1133 : }
1134 : }
1135 1 : br = true;
1136 1 : break;
1137 : }
1138 : }
1139 : }
1140 6 : if (br) {
1141 1 : break;
1142 : }
1143 : }
1144 : }
1145 : }
1146 : }
1147 294 : if (slurSwap) {
1148 293 : lastSlurAdd = false;
1149 : }
1150 294 : restsForEmptyBeats(segment, measure, cr, l, static_cast<int>(track), tick);
1151 294 : createSlur(hasSlur, staffIdx, cr);
1152 294 : tick += cr->actualTicks();
1153 294 : measureLen += cr->actualTicks();
1154 : }
1155 80 : if (measureLen < measure->ticks()) {
1156 0 : score->setRest(tick, track, measure->ticks() - measureLen, false, nullptr, false);
1157 0 : m_continiousElementsBuilder->notifyUncompletedMeasure();
1158 : }
1159 : }
1160 :
1161 80 : if (bar == 1 && !mixChange) {
1162 13 : setTempo(temp, score->firstMeasure());
1163 : }
1164 80 : }
1165 :
1166 29 : for (auto n : slideList) {
1167 3 : Segment* segment = n->chord()->segment();
1168 3 : Measure* measure1 = segment->measure();
1169 3 : int segment_counter = 0;
1170 3 : while ((segment = segment->next1(SegmentType::ChordRest))
1171 3 : || ((measure1 = measure1->nextMeasure()) && (segment = measure1->first()))) {
1172 3 : if (!segment->isChordRestType()) {
1173 0 : continue;
1174 : }
1175 3 : bool br = false;
1176 3 : ChordRest* cr = segment->cr(n->track());
1177 3 : if (cr && cr->isChord()) {
1178 3 : Chord* c = toChord(cr);
1179 3 : ++segment_counter;
1180 3 : if (segment_counter > 2) {
1181 0 : break;
1182 : }
1183 3 : for (Note* nt : c->notes()) {
1184 3 : if (nt->string() == n->string()) {
1185 3 : for (auto e : nt->el()) {
1186 0 : if (e->isChordLine()) {
1187 0 : auto cl = toChordLine(e);
1188 0 : if (cl->chordLineType() == ChordLineType::PLOP || cl->chordLineType() == ChordLineType::SCOOP) {
1189 0 : br = true;
1190 0 : break;
1191 : }
1192 : }
1193 : }
1194 3 : if (br) {
1195 0 : break;
1196 : }
1197 3 : Glissando* s = new Glissando(n);
1198 3 : s->setStartElement(n);
1199 3 : s->setTick(n->chord()->segment()->tick());
1200 3 : s->setTrack(n->track());
1201 3 : s->setGlissandoType(GlissandoType::STRAIGHT);
1202 3 : s->setEndElement(nt);
1203 3 : s->setTick2(nt->chord()->segment()->tick());
1204 3 : s->setTrack2(n->track());
1205 3 : score->addElement(s);
1206 3 : br = true;
1207 3 : break;
1208 : }
1209 : }
1210 3 : if (br) {
1211 3 : break;
1212 : }
1213 : }
1214 : }
1215 : }
1216 :
1217 26 : m_continiousElementsBuilder->addElementsToScore();
1218 26 : m_guitarBendImporter->addElementsToScore();
1219 26 : addTunings();
1220 26 : utils::addPlayCountTexts(score);
1221 :
1222 26 : return true;
1223 : }
1224 : } // namespace mu::iex::guitarpro
|