LCOV - code coverage report
Current view: top level - src/importexport/guitarpro/internal - importgtp-gp4.cpp Coverage Total Hit
Test: filtered_coverage.info Lines: 71.2 % 815 580
Test Date: 2026-11-05 04:07:02

            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
        

Generated by: LCOV version 2.0-1