LCOV - code coverage report
Current view: top level - src/importexport/guitarpro/internal/gtp - gpconverter.cpp Coverage Total Hit
Test: filtered_coverage.info Lines: 83.7 % 1859 1556
Test Date: 2026-11-05 04:07:02

            Line data    Source code
       1              : #include "gpconverter.h"
       2              : 
       3              : #include "engraving/dom/pitchspelling.h"
       4              : #include "translation.h"
       5              : 
       6              : #include "gpdommodel.h"
       7              : 
       8              : #include "engraving/dom/arpeggio.h"
       9              : #include "engraving/dom/bend.h"
      10              : #include "engraving/dom/box.h"
      11              : #include "engraving/dom/bracketitem.h"
      12              : #include "engraving/editing/editstaffbrackets.h"
      13              : #include "engraving/dom/chord.h"
      14              : #include "engraving/dom/chordline.h"
      15              : #include "engraving/dom/clef.h"
      16              : #include "engraving/dom/deadslapped.h"
      17              : #include "engraving/dom/drumset.h"
      18              : #include "engraving/dom/dynamic.h"
      19              : #include "engraving/dom/factory.h"
      20              : #include "engraving/dom/fermata.h"
      21              : #include "engraving/dom/fingering.h"
      22              : #include "engraving/dom/fret.h"
      23              : #include "engraving/dom/glissando.h"
      24              : #include "engraving/dom/guitarbend.h"
      25              : #include "engraving/dom/gradualtempochange.h"
      26              : #include "engraving/dom/hammeronpulloff.h"
      27              : #include "engraving/dom/harmony.h"
      28              : #include "engraving/dom/instrchange.h"
      29              : #include "engraving/dom/jump.h"
      30              : #include "engraving/dom/keysig.h"
      31              : #include "engraving/dom/lyrics.h"
      32              : #include "engraving/dom/marker.h"
      33              : #include "engraving/dom/measure.h"
      34              : #include "engraving/dom/measurerepeat.h"
      35              : #include "engraving/dom/note.h"
      36              : #include "engraving/dom/ottava.h"
      37              : #include "engraving/dom/part.h"
      38              : #include "engraving/dom/rehearsalmark.h"
      39              : #include "engraving/dom/rest.h"
      40              : #include "engraving/dom/score.h"
      41              : #include "engraving/dom/slur.h"
      42              : #include "engraving/dom/spanner.h"
      43              : #include "engraving/dom/staff.h"
      44              : #include "engraving/dom/stafftext.h"
      45              : #include "engraving/dom/tapping.h"
      46              : #include "engraving/dom/tempotext.h"
      47              : #include "engraving/dom/text.h"
      48              : #include "engraving/dom/tie.h"
      49              : #include "engraving/dom/timesig.h"
      50              : #include "engraving/dom/tremolosinglechord.h"
      51              : #include "engraving/dom/tripletfeel.h"
      52              : #include "engraving/dom/tuplet.h"
      53              : #include "engraving/dom/volta.h"
      54              : #include "engraving/dom/capo.h"
      55              : #include "engraving/dom/stringtunings.h"
      56              : #include "engraving/types/symid.h"
      57              : 
      58              : #include "engraving/editing/editchord.h"
      59              : 
      60              : #include "../utils.h"
      61              : #include "../guitarprodrumset.h"
      62              : 
      63              : #include "log.h"
      64              : 
      65              : using namespace mu::engraving;
      66              : 
      67              : namespace mu::iex::guitarpro {
      68           22 : static mu::engraving::JumpType jumpType(const String& typeString)
      69              : {
      70              :     static const std::map<String, JumpType> types {
      71            0 :         { u"DaCapo", JumpType::DC },
      72            0 :         { u"DaSegno", JumpType::DS },
      73            0 :         { u"DaCapoAlFine", JumpType::DC_AL_FINE },
      74            0 :         { u"DaCapoAlCoda", JumpType::DC_AL_CODA },
      75            0 :         { u"DaCapoAlDoubleCoda", JumpType::DC_AL_DBLCODA },
      76            0 :         { u"DaSegnoAlCoda", JumpType::DS_AL_CODA },
      77            0 :         { u"DaSegnoAlDoubleCoda", JumpType::DS_AL_DBLCODA },
      78            0 :         { u"DaSegnoAlFine", JumpType::DS_AL_FINE },
      79            0 :         { u"DaSegnoSegno", JumpType::DSS },
      80            0 :         { u"DaSegnoSegnoAlCoda", JumpType::DSS_AL_CODA },
      81            0 :         { u"DaSegnoSegnoAlDoubleCoda", JumpType::DSS_AL_DBLCODA },
      82            0 :         { u"DaSegnoSegnoAlFine", JumpType::DSS_AL_FINE },
      83           36 :     };
      84              : 
      85           22 :     auto it = types.find(typeString);
      86           22 :     if (it != types.end()) {
      87           22 :         return it->second;
      88              :     }
      89              : 
      90            0 :     LOGE() << "wrong jump type";
      91            0 :     return JumpType::USER;
      92            1 : }
      93              : 
      94           14 : static mu::engraving::MarkerType markerType(const String& typeString)
      95              : {
      96              :     static const std::map<String, MarkerType> types {
      97            0 :         { u"Segno", MarkerType::SEGNO },
      98            0 :         { u"SegnoSegno", MarkerType::VARSEGNO },
      99            0 :         { u"Coda", MarkerType::CODA },
     100            0 :         { u"DoubleCoda", MarkerType::VARCODA },
     101            0 :         { u"Fine", MarkerType::FINE },
     102            0 :         { u"DaCoda", MarkerType::DA_CODA },
     103            0 :         { u"DaDoubleCoda", MarkerType::DA_DBLCODA },
     104           23 :     };
     105              : 
     106           14 :     auto it = types.find(typeString);
     107           14 :     if (it != types.end()) {
     108           14 :         return it->second;
     109              :     }
     110              : 
     111            0 :     LOGE() << "wrong direction marker type";
     112            0 :     return MarkerType::USER;
     113            1 : }
     114              : 
     115            0 : static mu::engraving::TripletFeelType tripletFeelType(GPMasterBar::TripletFeelType tf)
     116              : {
     117              :     static const std::map<GPMasterBar::TripletFeelType, TripletFeelType> types {
     118              :         { GPMasterBar::TripletFeelType::Triplet8th, TripletFeelType::TRIPLET_8TH },
     119              :         { GPMasterBar::TripletFeelType::Triplet16th, TripletFeelType::TRIPLET_16TH },
     120              :         { GPMasterBar::TripletFeelType::Dotted8th, TripletFeelType::DOTTED_8TH },
     121              :         { GPMasterBar::TripletFeelType::Dotted16th, TripletFeelType::DOTTED_16TH },
     122              :         { GPMasterBar::TripletFeelType::Scottish8th, TripletFeelType::SCOTTISH_8TH },
     123              :         { GPMasterBar::TripletFeelType::Scottish16th, TripletFeelType::SCOTTISH_16TH },
     124              :         { GPMasterBar::TripletFeelType::None, TripletFeelType::NONE }
     125            0 :     };
     126              : 
     127            0 :     auto it = types.find(tf);
     128            0 :     if (it != types.end()) {
     129            0 :         return it->second;
     130              :     }
     131              : 
     132            0 :     return TripletFeelType::NONE;
     133              : }
     134              : 
     135         1631 : static std::pair<bool, mu::engraving::OttavaType> ottavaType(GPBeat::OttavaType t)
     136              : {
     137              :     static const std::map<GPBeat::OttavaType, mu::engraving::OttavaType> types {
     138              :         { GPBeat::OttavaType::va8,  OttavaType::OTTAVA_8VA },
     139              :         { GPBeat::OttavaType::vb8,  OttavaType::OTTAVA_8VB },
     140              :         { GPBeat::OttavaType::ma15, OttavaType::OTTAVA_15MA },
     141              :         { GPBeat::OttavaType::mb15, OttavaType::OTTAVA_15MB }
     142         1633 :     };
     143              : 
     144         1631 :     auto it = types.find(t);
     145         1631 :     if (it != types.end()) {
     146           60 :         return { true, it->second };
     147              :     }
     148              : 
     149         1571 :     return { false, OttavaType::OTTAVA_8VA };
     150              : }
     151              : 
     152           46 : static GPBeat::HarmonicMarkType harmonicTypeNoteToBeat(GPNote::Harmonic::Type t)
     153              : {
     154              :     static const std::map<GPNote::Harmonic::Type, GPBeat::HarmonicMarkType> types {
     155              :         { GPNote::Harmonic::Type::Artificial, GPBeat::HarmonicMarkType::Artificial },
     156              :         { GPNote::Harmonic::Type::Pinch, GPBeat::HarmonicMarkType::Pinch },
     157              :         { GPNote::Harmonic::Type::Tap, GPBeat::HarmonicMarkType::Tap },
     158              :         { GPNote::Harmonic::Type::Semi, GPBeat::HarmonicMarkType::Semi },
     159              :         { GPNote::Harmonic::Type::FeedBack, GPBeat::HarmonicMarkType::FeedBack }
     160           48 :     };
     161              : 
     162           46 :     auto it = types.find(t);
     163           46 :     if (it != types.end()) {
     164           46 :         return it->second;
     165              :     }
     166              : 
     167            0 :     return GPBeat::HarmonicMarkType::None;
     168              : }
     169              : 
     170         2095 : static ContiniousElementsBuilder::ImportType ottavaToImportType(GPBeat::OttavaType t)
     171              : {
     172              :     static const std::map<GPBeat::OttavaType, ContiniousElementsBuilder::ImportType> types {
     173              :         { GPBeat::OttavaType::ma15, ContiniousElementsBuilder::ImportType::OTTAVA_MA15 },
     174              :         { GPBeat::OttavaType::va8, ContiniousElementsBuilder::ImportType::OTTAVA_VA8 },
     175              :         { GPBeat::OttavaType::vb8, ContiniousElementsBuilder::ImportType::OTTAVA_VB8 },
     176              :         { GPBeat::OttavaType::mb15, ContiniousElementsBuilder::ImportType::OTTAVA_MB15 }
     177         2097 :     };
     178              : 
     179         2095 :     auto it = types.find(t);
     180         2095 :     if (it != types.end()) {
     181           60 :         return it->second;
     182              :     }
     183              : 
     184         2035 :     return ContiniousElementsBuilder::ImportType::NONE;
     185              : }
     186              : 
     187         2095 : static ContiniousElementsBuilder::ImportType hairpinToImportType(GPBeat::Hairpin t)
     188              : {
     189              :     static const std::map<GPBeat::Hairpin, ContiniousElementsBuilder::ImportType> types {
     190              :         { GPBeat::Hairpin::Crescendo, ContiniousElementsBuilder::ImportType::HAIRPIN_CRESCENDO },
     191              :         { GPBeat::Hairpin::Decrescendo, ContiniousElementsBuilder::ImportType::HAIRPIN_DIMINUENDO }
     192         2097 :     };
     193              : 
     194         2095 :     auto it = types.find(t);
     195         2095 :     if (it != types.end()) {
     196           16 :         return it->second;
     197              :     }
     198              : 
     199         2079 :     return ContiniousElementsBuilder::ImportType::NONE;
     200              : }
     201              : 
     202           60 : static void setPitchByOttavaType(mu::engraving::Note* note, mu::engraving::OttavaType type)
     203              : {
     204           60 :     note->setPitch(clampPitchOctaved(note->pitch() - ottavaDefault[int(type)].shift));
     205           60 : }
     206              : 
     207              : static std::unordered_map<uint64_t, mu::engraving::StringData> stringDatas;
     208              : 
     209          221 : GPConverter::GPConverter(Score* score, std::unique_ptr<GPDomModel>&& gpDom, const muse::modularity::ContextPtr& iocCtx)
     210         1105 :     : muse::Contextable(iocCtx), _score(score), _gpDom(std::move(gpDom))
     211              : {
     212          221 :     _drumExtension = {
     213              :         { 91, 40 }, //Snare(rim shot)
     214              :         { 92, 42 }, //Hi Hat (half)
     215              :         { 93, 51 }, //Ride (edje)
     216              :         { 94, 59 }, //Ride (choke)
     217              :         { 95, 55 }, //Splash (choke)
     218              :         { 96, 52 }, //Chine(choke)
     219              :         { 97, 49 }, //Crash high (choke)
     220              :         { 98, 57 }, //Crash medium (choke)
     221              :         { 99, 56 }, //Cowbell low (hit)
     222              :         { 100, 56 },//Cowbell low (tip)
     223              :         { 101, 56 },//Cowbell medium (tip)
     224              :         { 102, 56 },//Cowbell high (hit)
     225              :         { 103, 56 },//Cowbell high (tip)
     226              :         { 104, 60 },//Hand (mute)
     227              :         { 105, 60 },//Hand (slap)
     228              :         { 106, 61 },//Hand (mute)
     229              :         { 107, 61 },//Hand (slap)
     230              :         { 108, 64 },//Conga low (slap)
     231              :         { 109, 64 },//Conga low (mute)
     232              :         { 110, 64 },//Conga high (slap)
     233              :         { 111, 54 },//Tambourine (return)
     234              :         { 112, 54 },//Tambourine (roll)
     235              :         { 113, 54 },//Tambourine (hand)
     236              :         { 114, 43 },//Grancassa (hit)
     237              :         { 115, 49 },//Piatti (hit)
     238              :         { 116, 49 },//Piatti (hand)
     239              :         { 117, 69 },//Cabasa (return)
     240              :         { 118, 70 },//Left Maraca (return)
     241              :         { 119, 70 },//Right Maraca (hit)
     242              :         { 120, 70 },//Right Maraca (return)
     243              :         { 122, 82 },//Shaker (return)
     244              :         { 123, 84 },//Bell Tree (return)
     245              :         { 124, 62 },//Golpe (thumb)
     246              :         { 125, 62 },//Golpe (finger)
     247              :         { 126, 59 },//Ride (middle)
     248              :         { 127, 59 }//Ride (bell)
     249          221 :     };
     250              : 
     251          221 :     _drumResolver = std::make_unique<GPDrumSetResolver>();
     252          221 :     _drumResolver->initGPDrum();
     253          221 :     m_continiousElementsBuilder = std::make_unique<ContiniousElementsBuilder>(_score);
     254          221 :     m_guitarBendImporter = std::make_unique<GuitarBendImporter>(_score);
     255          221 : }
     256              : 
     257            0 : const std::unique_ptr<GPDomModel>& GPConverter::gpDom() const
     258              : {
     259            0 :     return _gpDom;
     260              : }
     261              : 
     262          221 : void GPConverter::convertGP()
     263              : {
     264          221 :     setUpGPScore(_gpDom->score());
     265          221 :     setUpTracks(_gpDom->tracks());
     266          221 :     collectTempoMap(_gpDom->masterTracks());
     267              : 
     268          221 :     convert(_gpDom->masterBars());
     269              : 
     270          221 :     clearDefectedSpanner();
     271          221 :     fixPercussion();
     272          221 :     addCapos();
     273          221 :     utils::addPlayCountTexts(_score);
     274          221 : }
     275              : 
     276          221 : void GPConverter::fixPercussion()
     277              : {
     278              :     // After reading some of the GP files, there're
     279              :     // parts, which contain only one percussion instrument.
     280              :     // In this case the program value for this instrument will
     281              :     // be set to the pitch value of the notes of the instrument,
     282              :     // thus we need to reset this value to 0.
     283          460 :     for (size_t i = 0; i < _score->parts().size(); ++i) {
     284          239 :         mu::engraving::Part* pPart = _score->parts()[i];
     285          239 :         IF_ASSERT_FAILED(!!pPart) {
     286            0 :             continue;
     287              :         }
     288              : 
     289          239 :         mu::engraving::Instrument* pInstrument = pPart->instrument();
     290          239 :         if (!pInstrument) {
     291            0 :             continue;
     292              :         }
     293              : 
     294          239 :         if (!pInstrument->useDrumset()) {
     295          236 :             continue;
     296              :         }
     297              : 
     298            3 :         if (pPart->midiChannel() == PERC_CHANNEL) {
     299            3 :             pPart->setMidiProgram(0, 128);
     300              :         }
     301              :     }
     302          221 : }
     303              : 
     304           12 : void GPConverter::fillTuplet()
     305              : {
     306           12 :     if (m_nextTupletInfo.elements.empty() || !m_nextTupletInfo.tuplet) {
     307            0 :         LOGE() << "not able to add elements to tuplet";
     308            0 :         return;
     309              :     }
     310              : 
     311           12 :     Tuplet* tuplet = m_nextTupletInfo.tuplet;
     312           12 :     ChordRest* firstCr = m_nextTupletInfo.elements.front();
     313           12 :     tuplet->setTrack(firstCr->track());
     314           12 :     tuplet->setOwnershipParent(firstCr->measure());
     315           12 :     tuplet->setTick(firstCr->tick());
     316           12 :     tuplet->setBaseLen(Fraction(1, m_nextTupletInfo.lowestBase));
     317           12 :     tuplet->setTicks(m_nextTupletInfo.duration);
     318           12 :     setupTupletStyle(tuplet);
     319              : 
     320           62 :     for (ChordRest* elem : m_nextTupletInfo.elements) {
     321           50 :         tuplet->add(elem);
     322              :     }
     323              : 
     324              :     /// TODO: solve correctly within engraving
     325              :     /// avoiding brackets on single note
     326           12 :     if (tuplet->elements().size() == 1) {
     327            0 :         tuplet->setBracketType(TupletBracketType::SHOW_NO_BRACKET);
     328              :     }
     329              : 
     330           12 :     m_nextTupletInfo.elements.clear();
     331           12 :     m_nextTupletInfo.tuplet = nullptr;
     332           12 :     m_nextTupletInfo.duration = Fraction();
     333           12 :     m_nextTupletInfo.lowestBase = NextTupletInfo::LOWEST_BASE;
     334              : }
     335              : 
     336          221 : void GPConverter::convert(const std::vector<std::unique_ptr<GPMasterBar> >& masterBars)
     337              : {
     338          916 :     for (uint32_t mi = 0; mi < masterBars.size(); ++mi) {
     339          695 :         Context ctx;
     340          695 :         ctx.masterBarIndex = mi;
     341          695 :         convertMasterBar(masterBars.at(mi).get(), ctx);
     342              :     }
     343              : 
     344              :     // glueing line segment elements separated with rests
     345          221 :     m_continiousElementsBuilder->addElementsToScore();
     346              : 
     347          221 :     addTempoMap();
     348          221 :     addInstrumentChanges();
     349          221 :     m_guitarBendImporter->addElementsToScore();
     350              : 
     351          221 :     addFermatas();
     352          221 :     addContinuousSlideHammerOn();
     353          221 :     addTuning();
     354          221 : }
     355              : 
     356          695 : void GPConverter::convertMasterBar(const GPMasterBar* mB, Context ctx)
     357              : {
     358          695 :     Measure* measure = addMeasure(mB);
     359              : 
     360          695 :     addTimeSig(mB, measure);
     361          695 :     addKeySig(mB, measure);
     362          695 :     addBarline(mB, measure, ctx.masterBarIndex);
     363          695 :     addRepeat(mB, measure);
     364          695 :     collectFermatas(mB, measure);
     365          695 :     convertBars(mB->bars(), ctx);
     366          695 :     addTripletFeel(mB, measure);
     367          695 :     addSection(mB, measure);
     368          695 :     addDirection(mB, measure);
     369              : 
     370          695 :     fixEmptyMeasures();
     371          695 : }
     372              : 
     373          695 : void GPConverter::fixEmptyMeasures()
     374              : {
     375              :     // Get all ChordRest elems and sort them by staves
     376              :     // Also store root Segment ptr will need it later to delete some rest elems
     377          695 :     std::map<track_idx_t, std::vector<std::pair<Segment*, EngravingItem*> > > elems;
     378              : 
     379          695 :     size_t ntracks = _score->ntracks();
     380          695 :     SegmentType type = SegmentType::ChordRest;
     381          695 :     Measure* lastMeasure = _score->lastMeasure();
     382              : 
     383         2722 :     for (Segment* s = lastMeasure->segments().first(type); s; s = s->next(type)) {
     384        10767 :         for (track_idx_t i = 0; i < ntracks; ++i) {
     385         8740 :             auto e = s->element(i);
     386         8740 :             if (!e) {
     387         6425 :                 continue;
     388              :             }
     389         2315 :             elems[i / VOICES].push_back({ s, e });
     390              :         }
     391              :     }
     392              : 
     393         1473 :     for (const auto& [staffIdx, segItemPairs] : elems) {
     394          778 :         bool shouldClear = true;
     395         1100 :         for (const auto& p : segItemPairs) {
     396              :             // Don't need to do anything if there is not "rest" elem on a staff
     397          909 :             if (!p.second->isRest()) {
     398          587 :                 shouldClear = false;
     399          587 :                 break;
     400              :             }
     401              :         }
     402          778 :         if (shouldClear) {
     403              :             // Keep only one rest element in a bar and make its duration V_MEASURE
     404              :             // that way layout can recognize this bar as "empty"
     405              :             // and properly render mmrests
     406          191 :             if (segItemPairs.empty()) {
     407            0 :                 continue;
     408              :             }
     409          210 :             for (size_t i = 1; i < segItemPairs.size(); ++i) {
     410           19 :                 Rest* rest = toRest(segItemPairs.at(i).second);
     411           19 :                 if (Tuplet* tuplet = rest->tuplet()) {
     412            1 :                     tuplet->remove(rest);
     413              :                 }
     414              : 
     415           19 :                 segItemPairs.at(i).first->remove(rest);
     416              :             }
     417              : 
     418          191 :             Rest* rest = toRest(segItemPairs.at(0).second);
     419          191 :             rest->setTicks(lastMeasure->ticks());
     420          191 :             rest->setDurationType(DurationType::V_MEASURE);
     421          191 :             if (Tuplet* tuplet = rest->tuplet()) {
     422            1 :                 tuplet->remove(rest);
     423            1 :                 if (tuplet->elements().empty()) {
     424            1 :                     if (tuplet->tuplet()) {
     425            0 :                         tuplet->tuplet()->remove(tuplet);
     426              :                     }
     427              : 
     428            1 :                     delete tuplet;
     429              :                 }
     430              :             }
     431              :         }
     432              :     }
     433          695 : }
     434              : 
     435          695 : void GPConverter::convertBars(const std::vector<std::unique_ptr<GPBar> >& bars, Context ctx)
     436              : {
     437          695 :     ctx.curTrack = 0;
     438         1473 :     for (const auto& bar : bars) {
     439          778 :         m_chordExistsInBar = false;
     440          778 :         m_chordExistsForVoice.fill(false);
     441          778 :         convertBar(bar.get(), ctx);
     442          778 :         ctx.curTrack += VOICES;
     443              :     }
     444          695 : }
     445              : 
     446          778 : void GPConverter::convertBar(const GPBar* bar, Context ctx)
     447              : {
     448          778 :     addClef(bar, static_cast<int>(ctx.curTrack));
     449              : 
     450          778 :     if (addSimileMark(bar, static_cast<int>(ctx.curTrack))) {
     451            3 :         return;
     452              :     }
     453              : 
     454          775 :     convertVoices(bar->voices(), ctx);
     455          775 :     hideRestsInEmptyMeasures(ctx.curTrack, ctx.curTrack + VOICES);
     456              : }
     457              : 
     458          695 : void GPConverter::addBarline(const GPMasterBar* mB, Measure* measure, int32_t masterBarIndex)
     459              : {
     460              :     static bool insideFreeTime = false;
     461          695 :     size_t staves = _score->staves().size();
     462          695 :     bool lastMeasure = (masterBarIndex == static_cast<int32_t>(_gpDom->masterBars().size() - 1));
     463              : 
     464          695 :     if (!lastMeasure && mB->barlineType() == GPMasterBar::BarlineType::NORMAL) {
     465         1003 :         for (size_t staffIdx = 0; staffIdx < staves; ++staffIdx) {
     466          532 :             measure->setEndBarLineType(mu::engraving::BarLineType::NORMAL, staffIdx * VOICES);
     467              :         }
     468              :     }
     469              : 
     470          695 :     if (!lastMeasure && mB->barlineType() == GPMasterBar::BarlineType::DOUBLE) {
     471            7 :         for (size_t staffIdx = 0; staffIdx < staves; ++staffIdx) {
     472            4 :             measure->setEndBarLineType(mu::engraving::BarLineType::DOUBLE, staffIdx * VOICES);
     473              :         }
     474              :     }
     475              : 
     476          695 :     GPMasterBar::TimeSig sig = mB->timeSig();
     477          695 :     auto scoreTimeSig = Fraction(sig.numerator, sig.denominator);
     478              : 
     479          695 :     if (mB->freeTime()) {
     480            8 :         if (!lastMeasure && mB->barlineType() != GPMasterBar::BarlineType::DOUBLE) {
     481           13 :             for (size_t staffIdx = 0; staffIdx < staves; ++staffIdx) {
     482            7 :                 measure->setEndBarLineType(mu::engraving::BarLineType::BROKEN, staffIdx * VOICES);
     483              :             }
     484              :         }
     485            8 :         if (!insideFreeTime) {
     486            5 :             insideFreeTime = true;
     487              : 
     488              :             // Free time text
     489           12 :             for (size_t staffIdx = 0; staffIdx < staves; ++staffIdx) {
     490            7 :                 Segment* s = measure->getSegment(SegmentType::TimeSig, measure->tick());
     491            7 :                 StaffText* st = Factory::createStaffText(s);
     492            7 :                 st->setTrack(staffIdx * VOICES);
     493            7 :                 st->setPlainText(muse::mtrc("iex_guitarpro", "Free time", "time signature"));
     494            7 :                 s->add(st);
     495              : 
     496              :                 // if timeSig is different, it was added before, here we handle "freetime"
     497            7 :                 if (_lastTimeSig.numerator != sig.numerator
     498            7 :                     || _lastTimeSig.denominator != sig.denominator) {
     499            0 :                     return;
     500              :                 }
     501            7 :                 TimeSig* ts = Factory::createTimeSig(s);
     502            7 :                 ts->setSig(scoreTimeSig);
     503            7 :                 ts->setTrack(staffIdx * VOICES);
     504            7 :                 ts->setLargeParentheses(true);
     505            7 :                 s->add(ts);
     506              :             }
     507              :         }
     508              :     } else {
     509          687 :         insideFreeTime = false;
     510              :     }
     511          695 :     _lastTimeSig.numerator = sig.numerator;
     512          695 :     _lastTimeSig.denominator = sig.denominator;
     513              : }
     514              : 
     515          775 : void GPConverter::convertVoices(const std::vector<std::unique_ptr<GPVoice> >& voices, Context ctx)
     516              : {
     517          775 :     if (voices.empty()) {
     518          101 :         ctx.curTick = _score->lastMeasure()->tick();
     519          101 :         fillUncompletedMeasure(ctx);
     520              :     }
     521              : 
     522          775 :     track_idx_t currentTrackFirstVoice = ctx.curTrack;
     523         1499 :     for (const auto& voice : voices) {
     524          724 :         ctx.curTrack = currentTrackFirstVoice + voice->position();
     525          724 :         convertVoice(voice.get(), ctx);
     526              :     }
     527              : 
     528          775 :     bool hasFirstVoice = std::any_of(voices.begin(), voices.end(), [](const std::unique_ptr<GPVoice>& voice) {
     529          674 :         return voice->position() == 0;
     530              :     });
     531              : 
     532          775 :     if (!hasFirstVoice && _score->lastMeasure()) {
     533          116 :         _score->setRest(_score->lastMeasure()->tick(), currentTrackFirstVoice, _score->lastMeasure()->ticks(), true, nullptr);
     534              :     }
     535          775 : }
     536              : 
     537          724 : void GPConverter::convertVoice(const GPVoice* voice, Context ctx)
     538              : {
     539          724 :     ctx.curTick = _score->lastMeasure()->tick();
     540          724 :     convertBeats(voice->beats(), ctx);
     541          724 : }
     542              : 
     543          724 : void GPConverter::convertBeats(const std::vector<std::shared_ptr<GPBeat> >& beats, Context ctx)
     544              : {
     545          724 :     ChordRestContainer graceChords;
     546         2857 :     for (const auto& beat : beats) {
     547         2133 :         m_currentGPBeat = beat.get();
     548         2133 :         ctx.curTick = convertBeat(beat.get(), graceChords, ctx);
     549              :     }
     550              : 
     551          724 :     fillUncompletedMeasure(ctx);
     552          724 :     clearDefectedGraceChord(graceChords);
     553          724 : }
     554              : 
     555         2133 : Fraction GPConverter::convertBeat(const GPBeat* beat, ChordRestContainer& graceChords, Context ctx)
     556              : {
     557         2133 :     Measure* lastMeasure = _score->lastMeasure();
     558              : 
     559         2133 :     if (ctx.curTick >= lastMeasure->ticks() + lastMeasure->tick()) {
     560            2 :         return ctx.curTick;
     561              :     }
     562              : 
     563         2131 :     auto curSegment = lastMeasure->getSegment(SegmentType::ChordRest, ctx.curTick);
     564              : 
     565         2131 :     ChordRest* cr = addChordRest(beat, ctx);
     566         2131 :     if (cr) {
     567         2131 :         curSegment->setTicks(cr->ticks());
     568              :     }
     569         2131 :     if (engravingConfiguration()->guitarProImportExperimental() && beat->deadSlapped() && cr->isRest()) {
     570            0 :         Rest* rest = toRest(cr);
     571            0 :         curSegment->add(rest);
     572            0 :         DeadSlapped* dc = Factory::createDeadSlapped(rest);
     573            0 :         dc->setTrack(rest->track());
     574            0 :         rest->add(dc);
     575              :     } else {
     576         2131 :         if (beat->graceNotes() != GPBeat::GraceNotes::None) {
     577           36 :             if (cr->isRest()) {
     578            0 :                 delete cr;
     579            0 :                 return ctx.curTick;
     580              :             }
     581              : 
     582           36 :             curSegment->add(cr);
     583              : 
     584           36 :             graceChords.push_back({ cr, beat });
     585              : 
     586           36 :             return ctx.curTick;
     587              :         }
     588              : 
     589         2095 :         curSegment->add(cr);
     590              : 
     591         2095 :         if (cr->isChord()) {
     592         1595 :             m_chordExistsForVoice[ctx.curTrack % VOICES] = true;
     593         1595 :             m_chordExistsInBar = true;
     594              : 
     595         1595 :             if (beat->stemOrientationUserDefined()) {
     596            0 :                 toChord(cr)->setStemDirection(beat->stemOrientationUp() ? DirectionV::UP : DirectionV::DOWN);
     597              :             }
     598              : 
     599         1595 :             setBeamMode(beat, cr, lastMeasure, ctx.curTick);
     600              :         }
     601              : 
     602         2095 :         if (cr->isChord() && !graceChords.empty()) {
     603           24 :             int grIndex = 0;
     604              : 
     605           60 :             for (auto [pGrChord, pBeat] : graceChords) {
     606           36 :                 configureGraceChord(pBeat, pGrChord, beat->ottavaType());
     607           36 :                 if (pGrChord->isChord()) {
     608           36 :                     toChord(pGrChord)->setGraceIndex(grIndex++);
     609              :                 }
     610              : 
     611           36 :                 Fraction fr(1, (graceChords.size() == 1 ? 1 : 2) * 8);
     612           36 :                 pGrChord->setDurationType(TDuration(fr));
     613              : 
     614           36 :                 cr->add(pGrChord);
     615           36 :                 addLegato(pBeat, pGrChord);
     616              :             }
     617           24 :             graceChords.clear();
     618              :         }
     619              : 
     620         2095 :         convertNotes(beat->notes(), cr);
     621              : 
     622         2095 :         addTuplet(beat, cr);
     623         2095 :         addTimer(beat, cr);
     624         2095 :         addFreeText(beat, cr);
     625         2095 :         addFadding(beat, cr);
     626         2095 :         addHairPin(beat, cr);
     627         2095 :         addTremolo(beat, cr);
     628         2095 :         addPickStroke(beat, cr);
     629         2095 :         addDynamic(beat, cr);
     630         2095 :         addWah(beat, cr);
     631         2095 :         addGolpe(beat, cr);
     632         2095 :         addFretDiagram(beat, cr, ctx);
     633         2095 :         addBarre(beat, cr);
     634         2095 :         addTapping(beat, cr);
     635         2095 :         addSlapped(beat, cr);
     636         2095 :         addPopped(beat, cr);
     637         2095 :         addBrush(beat, cr);
     638         2095 :         addArpeggio(beat, cr);
     639         2095 :         addLyrics(beat, cr, ctx);
     640         2095 :         addLegato(beat, cr);
     641              : 
     642              :         // line segment elements
     643         2095 :         addOttava(beat, cr);
     644         2095 :         addLetRing(beat, cr);
     645         2095 :         addPalmMute(beat, cr);
     646         2095 :         addTrill(beat, cr);
     647         2095 :         addRasgueado(beat, cr);
     648         2095 :         addDive(beat, cr);
     649         2095 :         addPickScrape(beat, cr);
     650         2095 :         addHarmonicMark(beat, cr);
     651         2095 :         addVibratoLeftHand(beat, cr);
     652         2095 :         addVibratoWTremBar(beat, cr);
     653              :     }
     654              : 
     655         2095 :     ctx.curTick += cr->actualTicks();
     656              : 
     657         2095 :     return ctx.curTick;
     658              : }
     659              : 
     660         2131 : void GPConverter::convertNotes(const std::vector<std::shared_ptr<GPNote> >& notes, ChordRest* cr)
     661              : {
     662         4161 :     for (const auto& note : notes) {
     663         2030 :         convertNote(note.get(), cr);
     664              :     }
     665              : 
     666              :     //! NOTE: later notes order is used in linked staff to create ties, glissando
     667         2131 :     if (cr->isChord()) {
     668         1631 :         Chord* ch = toChord(cr);
     669         1631 :         ch->sortNotes();
     670         1631 :         mu::iex::guitarpro::utils::createGhostNoteParenGroups(ch);
     671              :     }
     672         2131 : }
     673              : 
     674         2030 : void GPConverter::convertNote(const GPNote* gpnote, ChordRest* cr)
     675              : {
     676         2030 :     if (!cr->isChord()) {
     677            0 :         return;
     678              :     }
     679              : 
     680         2030 :     Chord* ch = toChord(cr);
     681              : 
     682         2030 :     Note* note = mu::engraving::Factory::createNote(ch);
     683         2030 :     note->setTrack(cr->track());
     684         2030 :     cr->add(note);
     685         2030 :     setPitch(note, gpnote->midiPitch());
     686         2030 :     setTpc(note, gpnote->accidental());
     687              : 
     688         2030 :     Note* harmonicNote = addHarmonic(gpnote, note);
     689         2030 :     addBend(gpnote, note);
     690              : 
     691         2030 :     addLetRing(gpnote, note);
     692         2030 :     addPalmMute(gpnote, note);
     693         2030 :     note->setGhost(gpnote->ghostNote());
     694              : 
     695         2030 :     note->setDeadNote(gpnote->muted());
     696         2030 :     addAccent(gpnote, note);
     697         2030 :     addSlide(gpnote, note);
     698         2030 :     addPickScrape(gpnote, note);
     699         2030 :     collectHammerOn(gpnote, note);
     700         2030 :     addRightHandTapping(gpnote);
     701         2030 :     addLeftHandTapping(gpnote);
     702         2030 :     addStringNumber(gpnote, note);
     703         2030 :     addOrnament(gpnote, note);
     704         2030 :     addVibratoLeftHand(gpnote, note);
     705         2030 :     addTrill(gpnote, note);
     706         2030 :     addFingering(gpnote, note);
     707         2030 :     addTie(gpnote, note, _ties);
     708         2030 :     if (harmonicNote) {
     709           49 :         addTie(gpnote, harmonicNote, _harmonicTies);
     710              :     }
     711              : }
     712              : 
     713           36 : void GPConverter::configureGraceChord(const GPBeat* beat, ChordRest* cr, GPBeat::OttavaType type)
     714              : {
     715           36 :     convertNotes(beat->notes(), cr);
     716              : 
     717           36 :     if (!cr->isChord()) {
     718            0 :         return;
     719              :     }
     720              : 
     721           36 :     Chord* grChord = toChord(cr);
     722              : 
     723           36 :     if (GPBeat::GraceNotes::OnBeat == beat->graceNotes()) {
     724           16 :         grChord->setNoteType(NoteType::APPOGGIATURA);
     725              :     } else {
     726           20 :         grChord->setNoteType(NoteType::ACCIACCATURA);
     727              :     }
     728              : 
     729           36 :     const auto& [foundOttava, muOttavaType] = ottavaType(type);
     730           36 :     if (foundOttava) {
     731            0 :         for (Note* note : grChord->notes()) {
     732            0 :             setPitchByOttavaType(note, muOttavaType);
     733              :         }
     734              :     }
     735              : }
     736              : 
     737          695 : void GPConverter::addTimeSig(const GPMasterBar* mB, Measure* measure)
     738              : {
     739          695 :     GPMasterBar::TimeSig sig = mB->timeSig();
     740          695 :     Fraction tick = measure->tick();
     741          695 :     auto scoreTimeSig = Fraction(sig.numerator, sig.denominator);
     742          695 :     measure->setTicks(scoreTimeSig);
     743          695 :     size_t staves = _score->staves().size();
     744              : 
     745          695 :     if (_lastTimeSig.numerator == sig.numerator
     746          471 :         && _lastTimeSig.denominator == sig.denominator) {
     747          471 :         return;
     748              :     }
     749          224 :     _lastTimeSig.numerator = sig.numerator;
     750          224 :     _lastTimeSig.denominator = sig.denominator;
     751              : 
     752          469 :     for (size_t staffIdx = 0; staffIdx < staves; ++staffIdx) {
     753          245 :         Staff* staff = _score->staff(staffIdx);
     754          245 :         if (staff->staffType()->genTimesig()) {
     755          245 :             Segment* s = measure->getSegment(SegmentType::TimeSig, tick);
     756          245 :             TimeSig* t = Factory::createTimeSig(s);
     757          245 :             track_idx_t curTrack = staffIdx * VOICES;
     758          245 :             t->setTrack(curTrack);
     759          245 :             t->setSig(scoreTimeSig);
     760          245 :             if (mB->freeTime()) {
     761            7 :                 t->setLargeParentheses(true);
     762              :             }
     763          245 :             s->add(t);
     764              :         }
     765              :     }
     766              : }
     767              : 
     768          695 : void GPConverter::addRepeat(const GPMasterBar* mB, Measure* measure)
     769              : {
     770          695 :     addVolta(mB, measure);
     771              : 
     772          695 :     if (mB->repeat().type == GPMasterBar::Repeat::Type::None) {
     773          687 :         return;
     774              :     }
     775              : 
     776            8 :     if (mB->repeat().type == GPMasterBar::Repeat::Type::Start) {
     777            2 :         measure->setRepeatStart(true);
     778              :     }
     779            8 :     if (mB->repeat().type == GPMasterBar::Repeat::Type::End) {
     780            6 :         measure->setRepeatEnd(true);
     781              :     }
     782            8 :     if (mB->repeat().type == GPMasterBar::Repeat::Type::StartEnd) {
     783            0 :         measure->setRepeatStart(true);
     784            0 :         measure->setRepeatEnd(true);
     785              :     }
     786            8 :     measure->setRepeatCount(mB->repeat().count);
     787              : }
     788              : 
     789          695 : void GPConverter::addVolta(const GPMasterBar* mB, Measure* measure)
     790              : {
     791          695 :     if (mB->alternateEnding().empty()) {
     792          691 :         _lastVolta = nullptr;
     793          691 :         return;
     794              :     }
     795              : 
     796            4 :     if (_lastVolta && _lastVolta->endings().size() != mB->alternateEnding().size()) {
     797            2 :         _lastVolta = nullptr;
     798              :     }
     799              : 
     800            4 :     if (_lastVolta) {
     801            0 :         for (const auto& end : mB->alternateEnding()) {
     802            0 :             if (!_lastVolta->hasEnding(end)) {
     803            0 :                 _lastVolta = nullptr;
     804            0 :                 break;
     805              :             }
     806              :         }
     807              :     }
     808              : 
     809            4 :     doAddVolta(mB, measure);
     810              : }
     811              : 
     812            4 : void GPConverter::doAddVolta(const GPMasterBar* mB, Measure* measure)
     813              : {
     814              :     mu::engraving::Volta* volta;
     815            4 :     if (_lastVolta) {
     816            0 :         volta = _lastVolta;
     817            0 :         _score->removeElement(volta);
     818              :     } else {
     819            4 :         volta = new mu::engraving::Volta(_score->dummy());
     820            4 :         volta->setTick(measure->tick());
     821            4 :         _lastVolta = volta;
     822              :     }
     823              : 
     824            4 :     volta->endings().clear();
     825            4 :     volta->setTick2(measure->endTick());
     826              : 
     827            4 :     String str;
     828           10 :     for (const auto& end : mB->alternateEnding()) {
     829            6 :         volta->endings().push_back(end);
     830            6 :         if (str.isEmpty()) {
     831            4 :             str += String(u"%1").arg(end);
     832              :         } else {
     833            2 :             str += String(u"-%1").arg(end);
     834              :         }
     835              :     }
     836            4 :     volta->setText(str);
     837              : 
     838            4 :     _score->addElement(volta);
     839            4 : }
     840              : 
     841          695 : void GPConverter::addDirection(const GPMasterBar* mB, Measure* measure)
     842              : {
     843          731 :     for (const auto& dir : mB->directions()) {
     844           36 :         if (dir.type == GPMasterBar::Direction::Type::Jump) {
     845           22 :             Jump* jump = Factory::createJump(measure);
     846           22 :             jump->setJumpType(jumpType(dir.name));
     847           22 :             jump->setTrack(0);
     848           22 :             measure->add(jump);
     849              :         } else {
     850           14 :             Marker* marker = Factory::createMarker(measure);
     851           14 :             marker->setMarkerType(markerType(dir.name));
     852           14 :             marker->resetProperty(Pid::LABEL);
     853           14 :             marker->setTrack(0);
     854           14 :             measure->add(marker);
     855              :         }
     856              :     }
     857          695 : }
     858              : 
     859          695 : void GPConverter::addSection(const GPMasterBar* mB, Measure* measure)
     860              : {
     861          695 :     if (mB->section().first.isEmpty() && mB->section().second.isEmpty()) {
     862          692 :         return;
     863              :     }
     864              : 
     865            3 :     if (!mB->section().first.isEmpty()) {
     866            0 :         Segment* s = measure->getSegment(SegmentType::ChordRest, measure->tick());
     867            0 :         RehearsalMark* t = Factory::createRehearsalMark(s);
     868            0 :         t->setPlainText(mB->section().first);
     869            0 :         t->setType(RehearsalMark::Type::Main);
     870            0 :         t->setTrack(0);
     871            0 :         s->add(t);
     872              :     }
     873            3 :     if (!mB->section().second.isEmpty()) {
     874            3 :         Segment* s = measure->getSegment(SegmentType::ChordRest, measure->tick());
     875            3 :         RehearsalMark* t = Factory::createRehearsalMark(s);
     876            3 :         t->setPlainText(mB->section().second);
     877            3 :         t->setType(RehearsalMark::Type::Additional);
     878            3 :         t->setTrack(0);
     879            3 :         s->add(t);
     880              :     }
     881              : }
     882              : 
     883          695 : void GPConverter::addTripletFeel(const GPMasterBar* mB, Measure* measure)
     884              : {
     885          695 :     if (mB->tripletFeel() == _lastTripletFeel) {
     886          695 :         return; // if last triplet of last measure is equal current dont create new system text
     887              :     }
     888              : 
     889            0 :     Segment* segment = measure->getSegment(SegmentType::ChordRest, measure->tick());
     890            0 :     TripletFeelType type = tripletFeelType(mB->tripletFeel());
     891            0 :     TripletFeel* tripletFeel = Factory::createTripletFeel(segment, type);
     892            0 :     _lastTripletFeel = mB->tripletFeel();
     893            0 :     tripletFeel->setTrack(0);
     894            0 :     segment->add(tripletFeel);
     895              : }
     896              : 
     897          695 : void GPConverter::addKeySig(const GPMasterBar* mB, Measure* measure)
     898              : {
     899          302 :     auto convertKeySig = [](GPMasterBar::KeySig::Accidentals kS) {
     900          302 :         if (kS == GPMasterBar::KeySig::Accidentals::C_B) {
     901            4 :             return Key::C_B;
     902          298 :         } else if (kS == GPMasterBar::KeySig::Accidentals::G_B) {
     903            5 :             return Key::G_B;
     904          293 :         } else if (kS == GPMasterBar::KeySig::Accidentals::D_B) {
     905            5 :             return Key::D_B;
     906          288 :         } else if (kS == GPMasterBar::KeySig::Accidentals::A_B) {
     907            4 :             return Key::A_B;
     908          284 :         } else if (kS == GPMasterBar::KeySig::Accidentals::E_B) {
     909            4 :             return Key::E_B;
     910          280 :         } else if (kS == GPMasterBar::KeySig::Accidentals::B_B) {
     911           14 :             return Key::B_B;
     912          266 :         } else if (kS == GPMasterBar::KeySig::Accidentals::F) {
     913            4 :             return Key::F;
     914          262 :         } else if (kS == GPMasterBar::KeySig::Accidentals::C) {
     915          222 :             return Key::C;
     916           40 :         } else if (kS == GPMasterBar::KeySig::Accidentals::G) {
     917           16 :             return Key::G;
     918           24 :         } else if (kS == GPMasterBar::KeySig::Accidentals::D) {
     919            4 :             return Key::D;
     920           20 :         } else if (kS == GPMasterBar::KeySig::Accidentals::A) {
     921            4 :             return Key::A;
     922           16 :         } else if (kS == GPMasterBar::KeySig::Accidentals::E) {
     923            4 :             return Key::E;
     924           12 :         } else if (kS == GPMasterBar::KeySig::Accidentals::B) {
     925            4 :             return Key::B;
     926            8 :         } else if (kS == GPMasterBar::KeySig::Accidentals::F_S) {
     927            4 :             return Key::F_S;
     928              :         } else {
     929            4 :             return Key::C_S;
     930              :         }
     931              :     };
     932              : 
     933          302 :     auto convertMode = [](GPMasterBar::KeySig::Mode m) {
     934          302 :         if (m == GPMasterBar::KeySig::Mode::Major) {
     935          252 :             return KeyMode::MAJOR;
     936              :         } else {
     937           50 :             return KeyMode::MINOR;
     938              :         }
     939              :     };
     940              : 
     941              :     using KS = GPMasterBar::KeySig::Accidentals;
     942              : 
     943          695 :     Fraction tick = measure->tick();
     944          695 :     size_t staves = _score->staves().size();
     945              : 
     946          302 :     auto getNumSharps = [this](int key) {
     947          302 :         if (key > 0) {
     948          164 :             for (size_t i = 0; i < m_sharpsToKeyConverter.size(); ++i) {
     949          164 :                 if (m_sharpsToKeyConverter.at(i) == key) {
     950           40 :                     return i;
     951              :                 }
     952              :             }
     953              :         } else {
     954          599 :             for (size_t i = 0; i < m_sharpsToFlatKeysConverter.size(); ++i) {
     955          599 :                 if (m_sharpsToFlatKeysConverter.at(i) == key) {
     956          262 :                     return i;
     957              :                 }
     958              :             }
     959              :         }
     960              :         // Never should get here
     961            0 :         return muse::nidx;
     962          695 :     };
     963              : 
     964         1473 :     for (size_t staffIdx = 0; staffIdx < staves; ++staffIdx) {
     965          778 :         if (!tick.isZero() && _lastKeySigs[staffIdx].accidentalCount == mB->keySig().accidentalCount) {
     966          476 :             continue;
     967              :         }
     968          302 :         int key = static_cast<int>(mB->keySig().accidentalCount);
     969              : 
     970          302 :         bool useFlats = mB->useFlats() || key < 0;
     971          302 :         size_t numSharps = getNumSharps(key);
     972          302 :         IF_ASSERT_FAILED(numSharps != muse::nidx) {
     973            0 :             LOGE() << "Unprocessable key for key signature";
     974            0 :             numSharps = 0;
     975              :         }
     976          302 :         numSharps = static_cast<int>(numSharps) % 12;
     977          302 :         if (useFlats) {
     978           60 :             key = m_sharpsToFlatKeysConverter.at(numSharps);
     979              :         } else {
     980          242 :             key = m_sharpsToKeyConverter.at(numSharps);
     981              :         }
     982              : 
     983          302 :         auto scoreKeySig = convertKeySig(static_cast<KS>(key));
     984          302 :         auto scoreMode = convertMode(mB->keySig().mode);
     985              : 
     986          302 :         Staff* staff = _score->staff(staffIdx);
     987          302 :         if (staff->staffType()->genTimesig()) {
     988          302 :             Segment* s = measure->getSegment(SegmentType::KeySig, tick);
     989          302 :             KeySig* t = mu::engraving::Factory::createKeySig(s);
     990          302 :             t->setTrack(staffIdx * VOICES);
     991          302 :             t->setKey(scoreKeySig);
     992          302 :             t->setMode(scoreMode);
     993          302 :             s->add(t);
     994          302 :             _lastKeySigs[staffIdx] = mB->keySig();
     995              :         }
     996              :     }
     997          695 : }
     998              : 
     999          221 : void GPConverter::setUpGPScore(const GPScore* gpscore)
    1000              : {
    1001          221 :     engravingConfiguration()->setGuitarProMultivoiceEnabled(gpscore->multiVoice());
    1002              : 
    1003              :     std::vector<String> fieldNames = { gpscore->title(), gpscore->subTitle(), gpscore->artist(),
    1004         1768 :                                        gpscore->album(), gpscore->composer(), gpscore->poet() };
    1005              : 
    1006              :     bool createTitleField
    1007         1497 :         = std::any_of(fieldNames.begin(), fieldNames.end(), [](const String& fieldName) { return !fieldName.isEmpty(); });
    1008              : 
    1009          221 :     if (!createTitleField && !engravingConfiguration()->guitarProImportExperimental()) {
    1010          211 :         return;
    1011              :     }
    1012              : 
    1013           10 :     MeasureBase* m = nullptr;
    1014           10 :     if (!_score->measures()->first()) {
    1015           10 :         m = Factory::createTitleVBox(_score);
    1016           10 :         _score->measures()->append(m);
    1017              :     } else {
    1018            0 :         m = _score->measures()->first();
    1019            0 :         if (!m->isVBox()) {
    1020            0 :             MeasureBase* mb = Factory::createTitleVBox(_score);
    1021            0 :             _score->addMeasure(mb, m);
    1022            0 :             m = mb;
    1023              :         }
    1024              :     }
    1025              : 
    1026           10 :     if (!gpscore->title().isEmpty() || engravingConfiguration()->guitarProImportExperimental()) {
    1027           10 :         Text* s = Factory::createText(m, TextStyleType::TITLE);
    1028           10 :         s->setPlainText(gpscore->title());
    1029           10 :         m->add(s);
    1030              :     }
    1031           15 :     if (!gpscore->subTitle().isEmpty() || !gpscore->artist().isEmpty() || !gpscore->album().isEmpty()
    1032           15 :         || engravingConfiguration()->guitarProImportExperimental()) {
    1033            9 :         Text* s = Factory::createText(m, TextStyleType::SUBTITLE);
    1034            9 :         String str;
    1035            9 :         if (!gpscore->subTitle().isEmpty()) {
    1036            5 :             str.append(gpscore->subTitle());
    1037              :         }
    1038            9 :         if (!gpscore->artist().isEmpty()) {
    1039            9 :             if (!str.isEmpty()) {
    1040            5 :                 str.append(u'\n');
    1041              :             }
    1042            9 :             str.append(gpscore->artist());
    1043              :         }
    1044            9 :         if (!gpscore->album().isEmpty()) {
    1045            9 :             if (!str.isEmpty()) {
    1046            9 :                 str.append(u'\n');
    1047              :             }
    1048            9 :             str.append(gpscore->album());
    1049              :         }
    1050            9 :         s->setPlainText(str);
    1051            9 :         m->add(s);
    1052            9 :     }
    1053           10 :     if (!gpscore->composer().isEmpty()) {
    1054            8 :         Text* s = Factory::createText(m, TextStyleType::COMPOSER);
    1055            8 :         s->setPlainText(muse::mtrc("iex_guitarpro", "Music by %1").arg(gpscore->composer()));
    1056            8 :         m->add(s);
    1057              :     }
    1058              : 
    1059           10 :     if (!gpscore->poet().isEmpty() || engravingConfiguration()->guitarProImportExperimental()) {
    1060            7 :         Text* s = Factory::createText(m, TextStyleType::LYRICIST);
    1061            7 :         if (!gpscore->poet().isEmpty()) {
    1062            7 :             s->setPlainText(muse::mtrc("iex_guitarpro", "Words by %1").arg(gpscore->poet()));
    1063              :         }
    1064              : 
    1065            7 :         m->add(s);
    1066              :     }
    1067          442 : }
    1068              : 
    1069          221 : void GPConverter::setUpTracks(const std::map<int, std::unique_ptr<GPTrack> >& tracks)
    1070              : {
    1071          221 :     stringDatas.clear();
    1072          460 :     for (const auto& track : tracks) {
    1073          239 :         setUpTrack(track.second);
    1074              :     }
    1075          221 : }
    1076              : 
    1077          239 : void GPConverter::setUpTrack(const std::unique_ptr<GPTrack>& tR)
    1078              : {
    1079          239 :     int programm = tR->programm();
    1080          239 :     int midiChannel = tR->midiChannel();
    1081              : 
    1082          239 :     int idx = tR->idx() + 1; // 0 is invalid index
    1083              : 
    1084          239 :     Part* part = new Part(_score);
    1085          239 :     part->setPlainLongName(tR->name());
    1086          239 :     part->setPlainShortName(tR->shortName());
    1087          239 :     part->setId(idx);
    1088              : 
    1089          239 :     _score->appendPart(part);
    1090          481 :     for (size_t staffIdx = 0; staffIdx < tR->staffCount(); staffIdx++) {
    1091          242 :         Staff* s = Factory::createStaff(part);
    1092          242 :         _score->appendStaff(s);
    1093              :     }
    1094              : 
    1095          239 :     if (tR->staffCount() > 1) {
    1096            3 :         EditStaffBrackets::addBracket(_score, part->staff(0)->idx(),
    1097            3 :                                       mu::engraving::Factory::createBracketItem(_score->dummy(), BracketType::BRACE, 2));
    1098            3 :         part->staff(0)->setBarLineSpan(true);
    1099              :     }
    1100              : 
    1101          239 :     part->setMidiProgram(programm);
    1102          239 :     part->setMidiChannel(midiChannel);
    1103              : 
    1104          239 :     int vol_val = static_cast<int>(std::lround(tR->rse().volume * 127));
    1105          239 :     part->instrument()->channel(0)->setVolume(std::clamp(vol_val, 0, 127));
    1106              : 
    1107          239 :     int pan_val = static_cast<int>(std::lround(tR->rse().pan * 127));
    1108          239 :     part->instrument()->channel(0)->setPan(std::clamp(pan_val, 0, 127));
    1109              : 
    1110          239 :     Instrument* instr = part->instrument();
    1111          239 :     instr->setSingleNoteDynamics(false);
    1112          239 :     instr->setTranspose(tR->transpose());
    1113              : 
    1114          239 :     if (midiChannel == PERC_CHANNEL) {
    1115            3 :         String drumInstrName = tR->instrument();
    1116            3 :         if (!drumInstrName.empty()) {
    1117            0 :             part->setShortName(drumInstrName);
    1118              :         }
    1119              : 
    1120            3 :         Staff* staff = part->staff(0);
    1121            3 :         StaffTypes type = StaffTypes::PERC_DEFAULT;
    1122            3 :         if (auto it = drumset::PERC_STAFF_LINES_FROM_INSTRUMENT.find(tR->name().toStdString());
    1123            3 :             it != drumset::PERC_STAFF_LINES_FROM_INSTRUMENT.end()) {
    1124            0 :             drumset::initGuitarProPercussionSet(it->second);
    1125            0 :             drumset::setInstrumentDrumset(part->instrument(), it->second);
    1126            0 :             switch (it->second.numLines) {
    1127            0 :             case 1:
    1128            0 :                 type = StaffTypes::PERC_1LINE;
    1129            0 :                 break;
    1130            0 :             case 2:
    1131            0 :                 type = StaffTypes::PERC_2LINE;
    1132            0 :                 break;
    1133            0 :             case 3:
    1134            0 :                 type = StaffTypes::PERC_3LINE;
    1135            0 :                 break;
    1136            0 :             default:
    1137            0 :                 type = StaffTypes::PERC_DEFAULT;
    1138            0 :                 break;
    1139              :             }
    1140              :         } else {
    1141            3 :             drumset::initGuitarProDrumset();
    1142            3 :             part->instrument()->setDrumset(drumset::gpDrumset);
    1143              :         }
    1144            3 :         staff->setStaffType(Fraction(0, 1), *StaffType::preset(type));
    1145            3 :     } else {
    1146          236 :         auto staffProperties = tR->staffProperties();
    1147              : 
    1148          236 :         int capoFret = staffProperties.capoFret;
    1149              : 
    1150          236 :         m_capoParams.insert_or_assign(part->id().toUint64(), capoFret);
    1151          236 :         auto tuning = staffProperties.tuning;
    1152          236 :         bool usePresetTable = staffProperties.ignoreFlats;
    1153              : 
    1154          236 :         std::array<uint64_t, 3> flatPresets{ 0x3f3a36312c27, 0x3c37332e2924, 0x3f3a36312c25 };
    1155              : 
    1156          236 :         uint64_t k = 0;
    1157         1635 :         for (size_t i = 0; i < tuning.size(); ++i) {
    1158         1399 :             k |= (uint64_t)tuning[i] << 8 * i;
    1159              :         }
    1160              :         bool useFlats
    1161          236 :             = usePresetTable ? std::find(flatPresets.begin(), flatPresets.end(), k) != flatPresets.end() : staffProperties.useFlats;
    1162          236 :         auto fretCount = staffProperties.fretCount;
    1163              : 
    1164          236 :         if (tuning.empty()) {
    1165            2 :             tuning = utils::standardTuningFor(25, 6); // 6 string guitar
    1166              :         }
    1167              : 
    1168          236 :         int transpose = tR->transpose();
    1169         1647 :         for (auto& t : tuning) {
    1170         1411 :             t -= transpose;
    1171              :         }
    1172              : 
    1173          236 :         StringData stringData = StringData(fretCount, static_cast<int>(tuning.size()), tuning.data(), useFlats);
    1174          236 :         stringDatas.insert_or_assign(part->id().toUint64(), stringData);
    1175              :         // We're using Tuning String for non-standard string data
    1176              :         // Instrument string data should be set to the standard
    1177          236 :         tuning = utils::standardTuningFor(programm, (int)tuning.size());
    1178         1650 :         for (auto& t : tuning) {
    1179         1414 :             t -= tR->transpose();
    1180              :         }
    1181          236 :         stringData = StringData(fretCount, static_cast<int>(tuning.size()), tuning.data());
    1182          236 :         instr->setStringData(stringData);
    1183          236 :     }
    1184          239 : }
    1185              : 
    1186          221 : void GPConverter::collectTempoMap(const GPMasterTracks* mTr)
    1187              : {
    1188          444 :     for (const auto& temp : mTr->tempoMap()) {
    1189          223 :         _tempoMap.insert(std::make_pair(temp.bar, temp));
    1190              :     }
    1191          221 : }
    1192              : 
    1193          695 : void GPConverter::collectFermatas(const GPMasterBar* mB, Measure* measure)
    1194              : {
    1195          705 :     for (const auto& ferm : mB->fermatas()) {
    1196           10 :         _fermatas.push_back(std::make_pair(measure, ferm));
    1197              :     }
    1198          695 : }
    1199              : 
    1200          825 : void GPConverter::fillUncompletedMeasure(const Context& ctx)
    1201              : {
    1202          825 :     if (m_nextTupletInfo.tuplet) {
    1203            3 :         fillTuplet();
    1204              :     }
    1205              : 
    1206          825 :     Measure* lastMeasure = _score->lastMeasure();
    1207          825 :     int tickOffset = lastMeasure->ticks().ticks() + lastMeasure->tick().ticks() - ctx.curTick.ticks();
    1208          825 :     if (tickOffset > 0) {
    1209          173 :         _score->setRest(ctx.curTick, ctx.curTrack, Fraction::fromTicks(tickOffset), true, nullptr);
    1210          173 :         m_continiousElementsBuilder->notifyUncompletedMeasure();
    1211              :     }
    1212          825 : }
    1213              : 
    1214          775 : void GPConverter::hideRestsInEmptyMeasures(track_idx_t startTrack, track_idx_t endTrack)
    1215              : {
    1216         2948 :     for (Segment* segment = _score->lastMeasure()->first(SegmentType::ChordRest); segment;
    1217         2173 :          segment = segment->next(SegmentType::ChordRest)) {
    1218        10865 :         for (track_idx_t trackIdx = startTrack; trackIdx < endTrack; trackIdx++) {
    1219         8692 :             EngravingItem* element = segment->element(trackIdx);
    1220         8692 :             if (!element || !element->isRest()) {
    1221         7975 :                 continue;
    1222              :             }
    1223              : 
    1224          717 :             Rest* rest = toRest(element);
    1225          717 :             size_t voice = trackIdx % VOICES;
    1226          717 :             bool mainVoice = (voice == 0);
    1227              : 
    1228              :             // hiding rests in secondary voices for measures without any chords
    1229          717 :             if (!m_chordExistsInBar) {
    1230          210 :                 rest->setVisible(mainVoice);
    1231          210 :                 continue;
    1232              :             }
    1233              : 
    1234              :             // hiding rests in voices without chords
    1235          507 :             if (!m_chordExistsForVoice[voice]) {
    1236          152 :                 rest->setVisible(false);
    1237              :             }
    1238              :         }
    1239              :     }
    1240          775 : }
    1241              : 
    1242          221 : void GPConverter::addContinuousSlideHammerOn()
    1243              : {
    1244           53 :     auto searchEndNote = [] (Note* start) -> Note* {
    1245              :         ChordRest* nextCr;
    1246           53 :         if (toChord(start->parent())->ChordRest::isGrace()) {
    1247              :             //! this case when start note is a grace note so end note can be next note in grace notes
    1248              :             //! or parent note of grace notes
    1249            5 :             Chord* startChord =  toChord(start->parent());
    1250              : 
    1251            5 :             Chord* parentGrace = toChord(start->parent()->parent());
    1252              : 
    1253            5 :             auto it = parentGrace->graceNotes().begin();
    1254            7 :             for (; it != parentGrace->graceNotes().end(); ++it) {
    1255            7 :                 if (*it == startChord) {
    1256            5 :                     break;
    1257              :                 }
    1258              :             }
    1259              : 
    1260            5 :             if (it == parentGrace->graceNotes().end()) {
    1261            0 :                 nextCr = nullptr;
    1262           10 :             } else if (std::next(it) == parentGrace->graceNotes().end()) {
    1263            5 :                 nextCr = parentGrace;
    1264              :             } else {
    1265            0 :                 nextCr = *(++it);
    1266              :             }
    1267              :         } else {
    1268           48 :             nextCr = start->chord()->segment()->next1()->nextChordRest(start->track());
    1269           48 :             if (!nextCr) {
    1270            0 :                 return nullptr;
    1271              :             }
    1272              : 
    1273           48 :             if (nextCr->isChord() && !toChord(nextCr)->graceNotes().empty()) {
    1274            1 :                 Chord* firstGrace = toChord(nextCr)->graceNotes().front();
    1275            1 :                 bool isDiveGrace = false;
    1276            1 :                 if (!firstGrace->notes().empty()) {
    1277            1 :                     Note* gn = firstGrace->notes().front();
    1278            1 :                     isDiveGrace = gn->ghost() || gn->diveFor() || gn->diveBack();
    1279              :                 }
    1280            1 :                 if (!isDiveGrace) {
    1281            0 :                     nextCr = firstGrace;
    1282              :                 }
    1283              :             }
    1284              :         }
    1285              : 
    1286           53 :         if (!nextCr) {
    1287            0 :             return nullptr;
    1288              :         }
    1289              : 
    1290           53 :         if (!nextCr->isChord()) {
    1291            0 :             return nullptr;
    1292              :         }
    1293           53 :         auto nextChord = toChord(nextCr);
    1294           53 :         for (auto note : nextChord->notes()) {
    1295           53 :             if (note->string() == start->string() && (note->harmonic() == start->harmonic())) {
    1296           53 :                 return note;
    1297              :             }
    1298              :         }
    1299              : 
    1300            0 :         return nextChord->upNote();
    1301              :     };
    1302              : 
    1303          221 :     std::unordered_map<Note*, Slur*> legatoSlides;
    1304          221 :     std::unordered_map<Note*, HammerOnPullOff*> hammerOnPullOffs;
    1305          221 :     std::unordered_set<Chord*> hammerOnInChord;
    1306          274 :     for (const auto& slide : _slideHammerOnMap) {
    1307           53 :         Note* startNote = slide.first;
    1308           53 :         Note* endNote = searchEndNote(startNote);
    1309           53 :         if (!endNote || startNote->string() == -1 || startNote->fret() == endNote->fret()) {
    1310              :             //mistake in GP: such kind od slides shouldn't exist
    1311            0 :             continue;
    1312              :         }
    1313              : 
    1314           53 :         Note* currentStart = nullptr;
    1315           53 :         if (startNote->bendFor()) {
    1316            3 :             Note* bendNote = startNote;
    1317            3 :             GuitarBend* bend = bendNote->bendFor();
    1318              : 
    1319            4 :             while (bend) {
    1320            3 :                 if (bend->isDive()) {
    1321            2 :                     break;
    1322              :                 }
    1323              : 
    1324            1 :                 bendNote = bend->endNote();
    1325            1 :                 IF_ASSERT_FAILED(bendNote) {
    1326            0 :                     LOGE() << "glissando start note may be incorrect";
    1327            0 :                     break;
    1328              :                 }
    1329              : 
    1330            1 :                 if (!bendNote->chord()->isGraceAfter()) {
    1331            0 :                     break;
    1332              :                 }
    1333              : 
    1334            1 :                 currentStart = bendNote;
    1335            1 :                 bend = bendNote->bendFor();
    1336              :             }
    1337              : 
    1338            3 :             if (currentStart) {
    1339            1 :                 startNote = currentStart;
    1340              :             }
    1341              :         }
    1342              : 
    1343           53 :         Fraction startTick = startNote->chord()->tick();
    1344           53 :         Fraction endTick = endNote->chord()->tick();
    1345           53 :         track_idx_t track = startNote->track();
    1346              : 
    1347              :         /// Layout info
    1348           53 :         if (slide.second == SlideHammerOn::LegatoSlide || slide.second == SlideHammerOn::Slide) {
    1349           12 :             Glissando* gl = mu::engraving::Factory::createGlissando(startNote);
    1350           12 :             gl->setStartElement(startNote);
    1351           12 :             gl->setTrack(track);
    1352           12 :             gl->setTick(startTick);
    1353           12 :             gl->setTick2(endNote->chord()->tick());
    1354           12 :             gl->setEndElement(endNote);
    1355           12 :             gl->setText(u"");
    1356           12 :             gl->setGlissandoType(GlissandoType::STRAIGHT);
    1357           12 :             gl->setGlissandoShift(slide.second == SlideHammerOn::Slide);
    1358           12 :             gl->setGlissandoStyle(startNote->part()->instrument(startTick)->glissandoStyle());
    1359           12 :             _score->addElement(gl);
    1360              :         }
    1361              : 
    1362           53 :         if (slide.second == SlideHammerOn::LegatoSlide) {
    1363            8 :             if (legatoSlides.count(startNote) == 0) {
    1364            8 :                 Slur* slur = mu::engraving::Factory::createSlur(_score->dummy());
    1365            8 :                 if (slide.second == SlideHammerOn::LegatoSlide) {
    1366            8 :                     slur->setConnectedElement(mu::engraving::Slur::ConnectedElement::GLISSANDO);
    1367              :                 }
    1368              : 
    1369            8 :                 slur->setStartElement(startNote->chord());
    1370            8 :                 slur->setTrack(track);
    1371            8 :                 slur->setTick(startTick);
    1372            8 :                 slur->setTick2(endTick);
    1373            8 :                 legatoSlides[endNote] = slur;
    1374            8 :                 slur->setEndElement(endNote->chord());
    1375            8 :                 _score->addSpanner(slur);
    1376              :             } else {
    1377            0 :                 Slur* slur = legatoSlides[startNote];
    1378            0 :                 slur->setTick2(endTick);
    1379            0 :                 slur->setEndElement(endNote->chord());
    1380            0 :                 legatoSlides.erase(startNote);
    1381            0 :                 legatoSlides[endNote] = slur;
    1382              :             }
    1383           45 :         } else if (slide.second == SlideHammerOn::HammerOn) {
    1384           41 :             Chord* startChord = startNote->chord();
    1385           41 :             if (hammerOnInChord.find(startChord) != hammerOnInChord.end()) {
    1386            0 :                 continue;
    1387              :             }
    1388              : 
    1389           41 :             if (hammerOnPullOffs.count(startNote) == 0) {
    1390           35 :                 HammerOnPullOff* hammerOnPullOff = Factory::createHammerOnPullOff(_score->dummy());
    1391           35 :                 hammerOnPullOff->setTrack(startNote->track());
    1392           35 :                 hammerOnPullOff->setTick(startNote->tick());
    1393           35 :                 hammerOnPullOff->setTick2(endNote->tick());
    1394           35 :                 hammerOnPullOff->setStartElement(startChord);
    1395           35 :                 hammerOnPullOff->setEndElement(endNote->chord());
    1396           35 :                 _score->addElement(hammerOnPullOff);
    1397           35 :                 hammerOnPullOffs[endNote] = hammerOnPullOff;
    1398           35 :                 hammerOnInChord.insert(startChord);
    1399              :             } else {
    1400            6 :                 HammerOnPullOff* hammerOnPullOff = hammerOnPullOffs[startNote];
    1401            6 :                 hammerOnPullOff->setTick2(endTick);
    1402            6 :                 hammerOnPullOff->setEndElement(endNote->chord());
    1403            6 :                 hammerOnPullOffs.erase(startNote);
    1404            6 :                 hammerOnPullOffs[endNote] = hammerOnPullOff;
    1405              :             }
    1406              :         }
    1407              :     }
    1408          221 : }
    1409              : 
    1410          221 : void GPConverter::addFermatas()
    1411              : {
    1412           10 :     auto fermataType = [](const GPMasterBar::Fermata& fer) {
    1413           10 :         if (fer.type == GPMasterBar::Fermata::Type::Long) {
    1414            0 :             return SymId::fermataLongAbove;
    1415           10 :         } else if (fer.type == GPMasterBar::Fermata::Type::Short) {
    1416            0 :             return SymId::fermataShortAbove;
    1417              :         }
    1418           10 :         return SymId::fermataAbove;
    1419              :     };
    1420              : 
    1421          231 :     for (const auto& fr : _fermatas) {
    1422           10 :         const auto& measure = fr.first;
    1423           10 :         const auto& gpFermata = fr.second;
    1424           10 :         Fraction tick = Fraction::fromTicks(mu::engraving::Constants::DIVISION * gpFermata.offsetNum / gpFermata.offsetDenom);
    1425              :         // bellow how gtp fermata timeStretch converting to MU timeStretch
    1426           10 :         float convertingLength = 1.5f - gpFermata.length * 0.5f + gpFermata.length * gpFermata.length * 3;
    1427           10 :         Segment* seg = measure->getSegmentR(SegmentType::ChordRest, tick);
    1428              : 
    1429           20 :         for (size_t staffIdx = 0; staffIdx < _score->staves().size(); staffIdx++) {
    1430           10 :             Fermata* fermata = mu::engraving::Factory::createFermata(seg);
    1431           10 :             SymId type = fermataType(fr.second);
    1432           10 :             fermata->setSymIdAndTimeStretch(type);
    1433           10 :             fermata->setTimeStretch(convertingLength);
    1434           10 :             fermata->setTrack(staffIdx * VOICES);
    1435           10 :             seg->add(fermata);
    1436              :         }
    1437              :     }
    1438          221 : }
    1439              : 
    1440          223 : static Segment* findClosestSegment(Measure* m, Fraction tick)
    1441              : {
    1442          223 :     Segment* segment = m->findSegment(SegmentType::ChordRest, tick);
    1443          223 :     if (!segment) {
    1444            0 :         segment = m->getSegment(SegmentType::ChordRest, tick);
    1445            0 :         Segment* prev = segment->prev1(SegmentType::ChordRest);
    1446            0 :         Segment* next = segment->next1(SegmentType::ChordRest);
    1447            0 :         if (prev && next) {
    1448            0 :             segment = (next->tick() - segment->tick() < segment->tick() - prev->tick() ? next : prev);
    1449            0 :         } else if (prev) {
    1450            0 :             segment = prev;
    1451            0 :         } else if (next) {
    1452            0 :             segment = next;
    1453              :         }
    1454              :     }
    1455              : 
    1456          223 :     return segment;
    1457              : }
    1458              : 
    1459          221 : void GPConverter::addTempoMap()
    1460              : {
    1461          223 :     auto realTempo = [](const GPMasterTracks::Automation& temp) {
    1462              :         //real tempo - beats per second
    1463              :         //formula ro convert tempo from GTP tempo values
    1464          223 :         double tempo = temp.value;
    1465              : 
    1466          223 :         if (temp.tempoUnit == 0) {
    1467            0 :             return tempo;
    1468              :         }
    1469              : 
    1470          223 :         if (temp.tempoUnit != 5) {
    1471          223 :             return tempo * temp.tempoUnit / 2;
    1472              :         }
    1473              : 
    1474            0 :         if (temp.tempoUnit == 5) {
    1475            0 :             return tempo + tempo * 2;
    1476              :         }
    1477              : 
    1478            0 :         return tempo;
    1479              :     };
    1480              : 
    1481          221 :     int measureIdx = 0;
    1482          221 :     GradualTempoChange* _lastGradualTempoChange = nullptr;
    1483          221 :     int previousTempo = -1;
    1484              : 
    1485          916 :     for (auto m = _score->firstMeasure(); m; m = m->nextMeasure()) {
    1486          695 :         auto range = _tempoMap.equal_range(measureIdx); //one measure can have several tempo changing
    1487          695 :         measureIdx++;
    1488          918 :         for (auto tempIt = range.first; tempIt != range.second; tempIt++) {
    1489          223 :             Fraction tick = m->tick() + Fraction::fromTicks(
    1490          446 :                 tempIt->second.position * Constants::DIVISION * 4 * m->ticks().numerator() / m->ticks().denominator());
    1491          223 :             Segment* segment = findClosestSegment(m, tick);
    1492          223 :             double realTemp = realTempo(tempIt->second);
    1493          223 :             TempoText* tt = Factory::createTempoText(segment);
    1494          223 :             tt->setTempo((double)realTemp / 60);
    1495          223 :             String& labelText = tempIt->second.text;
    1496          223 :             String tempoText = String(u"<sym>metNoteQuarterUp</sym> = %1").arg(round(realTemp));
    1497              : 
    1498          223 :             if (!labelText.isEmpty()) {
    1499           28 :                 tempoText.prepend(labelText.append(Char(' ')));
    1500              :             }
    1501              : 
    1502          223 :             tt->setXmlText(tempoText);
    1503          223 :             tt->setTrack(0);
    1504          223 :             segment->add(tt);
    1505              : 
    1506          223 :             if (_lastGradualTempoChange) {
    1507            0 :                 _lastGradualTempoChange->setTick2(tick);
    1508            0 :                 GradualTempoChangeType tempoChangeType = GradualTempoChangeType::Undefined;
    1509            0 :                 String tempoChangeText;
    1510              : 
    1511            0 :                 if (realTemp > previousTempo) {
    1512            0 :                     tempoChangeType =  GradualTempoChangeType::Accelerando;
    1513            0 :                     tempoChangeText = u"accel.";
    1514              :                 } else {
    1515            0 :                     tempoChangeType = GradualTempoChangeType::Rallentando;
    1516            0 :                     tempoChangeText = u"rall.";
    1517              :                 }
    1518              : 
    1519            0 :                 _lastGradualTempoChange->setTempoChangeType(tempoChangeType);
    1520            0 :                 _lastGradualTempoChange->setBeginText(tempoChangeText);
    1521            0 :                 _lastGradualTempoChange->setContinueText(String(u"(%1)").arg(tempoChangeText));
    1522            0 :                 _score->addElement(_lastGradualTempoChange);
    1523            0 :                 _lastGradualTempoChange = nullptr;
    1524            0 :             }
    1525              : 
    1526          223 :             if (tempIt->second.linear) {
    1527            0 :                 GradualTempoChange* tempoChange = Factory::createGradualTempoChange(_score->dummy());
    1528            0 :                 tempoChange->setTick(tick);
    1529            0 :                 tempoChange->setTrack(0);
    1530            0 :                 _lastGradualTempoChange = tempoChange;
    1531              :             }
    1532              : 
    1533          223 :             previousTempo = realTemp;
    1534          223 :         }
    1535              :     }
    1536          221 : }
    1537              : 
    1538          221 : void GPConverter::addInstrumentChanges()
    1539              : {
    1540          460 :     for (const auto& track : _gpDom->tracks()) {
    1541          410 :         for (const auto& soundAutomation : track.second->soundAutomations()) {
    1542          171 :             int bar = soundAutomation.second.bar;
    1543          171 :             float pos = soundAutomation.second.position;
    1544              : 
    1545          171 :             int trackIdx = track.second->idx();
    1546              : 
    1547          171 :             int midiProgramm = 0;
    1548          171 :             String instrName;
    1549              : 
    1550          171 :             auto it = track.second->sounds().find(soundAutomation.second.value);
    1551          171 :             if (it == track.second->sounds().end()) {
    1552           48 :                 midiProgramm = track.second->programm();
    1553           48 :                 instrName = soundAutomation.second.value;
    1554              :             } else {
    1555          123 :                 midiProgramm = it->second.programm;
    1556          123 :                 instrName = it->second.label;
    1557              :             }
    1558              : 
    1559          171 :             if (bar == 0 && pos == 0 && midiProgramm == track.second->programm()) {
    1560              :                 // skipping the default instrument in the beginning of the track
    1561          154 :                 continue;
    1562              :             }
    1563              : 
    1564           17 :             Measure* m = _score->crMeasure(bar);
    1565           17 :             Segment* seg = m->first(SegmentType::ChordRest);
    1566           17 :             if (pos != 0) {
    1567              :                 // searching for correct segment to put instrument change
    1568           14 :                 Fraction tick = m->tick() + Fraction::fromTicks(pos * Constants::DIVISION);
    1569           14 :                 Segment* positionedSegment = m->findSegment(SegmentType::ChordRest, tick);
    1570           14 :                 if (positionedSegment) {
    1571           14 :                     seg = positionedSegment;
    1572              :                 }
    1573              :             }
    1574              : 
    1575           17 :             Instrument instr;
    1576           17 :             instr.setTranspose(track.second->transpose());
    1577           17 :             instr.setStringData(*_score->parts()[trackIdx]->instrument()->stringData());
    1578           17 :             instr.channel(0)->setProgram(midiProgramm);
    1579           17 :             if (track.second->midiChannel() == PERC_CHANNEL) {
    1580            0 :                 instr.setDrumset(drumset::gpDrumset);
    1581              :             }
    1582              : 
    1583           17 :             InstrumentChange* instrCh =  Factory::createInstrumentChange(seg, instr);
    1584           17 :             instrCh->setTrack(trackIdx * VOICES);
    1585           17 :             instrCh->setXmlText(instrName);
    1586              : 
    1587           17 :             seg->add(instrCh);
    1588          171 :         }
    1589              :     }
    1590          221 : }
    1591              : 
    1592          778 : bool GPConverter::addSimileMark(const GPBar* bar, int curTrack)
    1593              : {
    1594          778 :     if (bar->simileMark() == GPBar::SimileMark::None) {
    1595          775 :         return false;
    1596              :     }
    1597              : 
    1598            3 :     Measure* measure = _score->lastMeasure();
    1599            3 :     Segment* segment = measure->getSegment(SegmentType::ChordRest, measure->tick());
    1600            3 :     staff_idx_t staffIdx = track2staff(curTrack);
    1601              : 
    1602            3 :     switch (bar->simileMark()) {
    1603            3 :     case GPBar::SimileMark::Simple: {
    1604            3 :         MeasureRepeat* mr = Factory::createMeasureRepeat(segment);
    1605            3 :         mr->setTrack(curTrack);
    1606            3 :         mr->setTicks(measure->ticks());
    1607            3 :         mr->setNumMeasures(1);
    1608            3 :         segment->add(mr);
    1609            3 :         measure->setMeasureRepeatCount(1, staffIdx);
    1610            3 :         break;
    1611              :     }
    1612            0 :     case GPBar::SimileMark::FirstOfDouble: {
    1613            0 :         MeasureRepeat* mr = Factory::createMeasureRepeat(segment);
    1614            0 :         mr->setTrack(staff2track(staffIdx));
    1615            0 :         mr->setTicks(measure->ticks());
    1616            0 :         mr->setNumMeasures(2);
    1617            0 :         segment->add(mr);
    1618            0 :         measure->setMeasureRepeatCount(1, staffIdx);
    1619            0 :         break;
    1620              :     }
    1621            0 :     case GPBar::SimileMark::SecondOfDouble: {
    1622            0 :         Rest* r = Factory::createRest(segment);
    1623            0 :         r->setTrack(staff2track(staffIdx));
    1624            0 :         r->setTicks(measure->ticks());
    1625            0 :         r->setDurationType(DurationType::V_MEASURE);
    1626            0 :         segment->add(r);
    1627            0 :         measure->setMeasureRepeatCount(2, staffIdx);
    1628            0 :         break;
    1629              :     }
    1630            0 :     case GPBar::SimileMark::None:
    1631            0 :         break;
    1632              :     }
    1633            3 :     return true;
    1634              : }
    1635              : 
    1636          778 : void GPConverter::addClef(const GPBar* bar, int curTrack)
    1637              : {
    1638          778 :     auto convertClef = [](GPBar::Clef cl) {
    1639          778 :         if (cl.type == GPBar::ClefType::Neutral) {
    1640           32 :             return ClefType::PERC;
    1641          746 :         } else if (cl.type == GPBar::ClefType::G2) {
    1642          727 :             switch (cl.ottavia) {
    1643            2 :             case GPBar::OttaviaType::va8:
    1644            2 :                 return ClefType::G8_VA;
    1645            2 :             case GPBar::OttaviaType::vb8:
    1646            2 :                 return ClefType::G8_VB;
    1647            2 :             case GPBar::OttaviaType::ma15:
    1648            2 :                 return ClefType::G15_MA;
    1649            0 :             case GPBar::OttaviaType::mb15:
    1650            0 :                 return ClefType::G15_MB;
    1651          721 :             default:
    1652          721 :                 return ClefType::G;
    1653              :             }
    1654           19 :         } else if (cl.type == GPBar::ClefType::F4) {
    1655           15 :             switch (cl.ottavia) {
    1656            0 :             case GPBar::OttaviaType::va8:
    1657            0 :                 return ClefType::F_8VA;
    1658            0 :             case GPBar::OttaviaType::vb8:
    1659            0 :                 return ClefType::F8_VB;
    1660            0 :             case GPBar::OttaviaType::ma15:
    1661            0 :                 return ClefType::F_15MA;
    1662            0 :             case GPBar::OttaviaType::mb15:
    1663            0 :                 return ClefType::F15_MB;
    1664           15 :             default:
    1665           15 :                 return ClefType::F;
    1666              :             }
    1667            4 :         } else if (cl.type == GPBar::ClefType::C3) {
    1668            2 :             return ClefType::C3;
    1669            2 :         } else if (cl.type == GPBar::ClefType::C4 && cl.ottavia == GPBar::OttaviaType::vb8) {
    1670            0 :             return ClefType::C4_8VB;
    1671            2 :         } else if (cl.type == GPBar::ClefType::C4) {
    1672            2 :             return ClefType::C4;
    1673              :         }
    1674            0 :         return ClefType::G;
    1675              :     };
    1676              : 
    1677          778 :     Measure* lastMeasure = _score->lastMeasure();
    1678          778 :     Fraction tick = lastMeasure->tick();
    1679          778 :     ClefType clef = convertClef(bar->clef());
    1680              : 
    1681          778 :     if (tick == Fraction{ 0, 1 }) {
    1682          242 :         _clefs[curTrack] = bar->clef();
    1683          242 :         Staff* s = _score->staff(track2staff(curTrack));
    1684          242 :         s->setDefaultClefType(ClefTypeList(clef, clef));
    1685          766 :         return;
    1686              :     }
    1687              : 
    1688          536 :     if (_clefs.find(curTrack) != _clefs.end() && _clefs.at(curTrack) == bar->clef()) {
    1689          524 :         return;
    1690              :     }
    1691              : 
    1692           12 :     Segment* s = lastMeasure->getSegment(SegmentType::HeaderClef, tick);
    1693           12 :     Clef* cl = mu::engraving::Factory::createClef(s);
    1694           12 :     cl->setTrack(curTrack);
    1695           12 :     cl->setClefType(clef);
    1696              : 
    1697           12 :     s->add(cl);
    1698           12 :     _clefs[curTrack] = bar->clef();
    1699              : }
    1700              : 
    1701          695 : Measure* GPConverter::addMeasure(const GPMasterBar* mB)
    1702              : {
    1703          695 :     Fraction tick = _score->measures()->last() ? _score->measures()->last()->endTick() : Fraction(0, 1);
    1704          695 :     Measure* measure = Factory::createMeasure(_score);
    1705          695 :     measure->setTick(tick);
    1706          695 :     GPMasterBar::TimeSig sig = mB->timeSig();
    1707          695 :     auto scoreTimeSig = Fraction(sig.numerator, sig.denominator);
    1708          695 :     measure->setTimesig(scoreTimeSig);
    1709          695 :     measure->setTicks(scoreTimeSig);
    1710          695 :     _score->measures()->append(measure);
    1711              : 
    1712          695 :     return measure;
    1713              : }
    1714              : 
    1715         2131 : ChordRest* GPConverter::addChordRest(const GPBeat* beat, const Context& ctx)
    1716              : {
    1717         2148 :     auto rhythm = [](GPRhythm::RhytmType rhythm) {
    1718         2148 :         if (rhythm == GPRhythm::RhytmType::Whole) {
    1719          240 :             return 1;
    1720         1908 :         } else if (rhythm == GPRhythm::RhytmType::Half) {
    1721          169 :             return 2;
    1722         1739 :         } else if (rhythm == GPRhythm::RhytmType::Quarter) {
    1723         1378 :             return 4;
    1724          361 :         } else if (rhythm == GPRhythm::RhytmType::Eighth) {
    1725          176 :             return 8;
    1726          185 :         } else if (rhythm == GPRhythm::RhytmType::Sixteenth) {
    1727          149 :             return 16;
    1728           36 :         } else if (rhythm == GPRhythm::RhytmType::ThirtySecond) {
    1729           36 :             return 32;
    1730              :         } else {
    1731            0 :             return 64;
    1732              :         }
    1733              :     };
    1734              : 
    1735         2131 :     ChordRest* cr{ nullptr };
    1736         2131 :     if (beat->isRest()) {
    1737          500 :         cr = Factory::createRest(_score->dummy());
    1738              :     } else {
    1739         1631 :         cr = Factory::createChord(_score->dummy());
    1740              :     }
    1741              : 
    1742         2131 :     cr->setTrack(ctx.curTrack);
    1743              : 
    1744         2131 :     Fraction fr(1, rhythm(beat->lenth().second));
    1745         2148 :     for (int dot = 1; dot <= beat->lenth().first; dot++) {
    1746           17 :         fr += Fraction(1, rhythm(beat->lenth().second) * 2 * dot);
    1747              :     }
    1748              : 
    1749         2131 :     cr->setTicks(fr);
    1750         2131 :     cr->setDurationType(TDuration(fr));
    1751              : 
    1752         2131 :     return cr;
    1753              : }
    1754              : 
    1755         2030 : void GPConverter::addFingering(const GPNote* gpnote, Note* note)
    1756              : {
    1757         2030 :     if (gpnote->leftFingering().isEmpty() && gpnote->rightFingering().isEmpty()) {
    1758         2008 :         return;
    1759              :     }
    1760              : 
    1761           12 :     auto scoreFinger = [](const String& str) {
    1762           12 :         if (str == u"Open") {
    1763            0 :             return String(u'O');
    1764              :         }
    1765           12 :         return str;
    1766              :     };
    1767              : 
    1768           22 :     if (!gpnote->leftFingering().isEmpty()) {
    1769           12 :         Fingering* f = Factory::createFingering(note);
    1770           12 :         f->setPlainText(scoreFinger(gpnote->leftFingering()));
    1771           12 :         note->add(f);
    1772              :     }
    1773           22 :     if (!gpnote->rightFingering().isEmpty()) {
    1774           10 :         Fingering* f = Factory::createFingering(note);
    1775           10 :         f->setPlainText(gpnote->rightFingering());
    1776           10 :         note->add(f);
    1777              :     }
    1778              : }
    1779              : 
    1780         2030 : void GPConverter::addStringNumber(const GPNote* gpnote, Note* note)
    1781              : {
    1782         2030 :     if (!gpnote->showStringNumber()) {
    1783         2030 :         return;
    1784              :     }
    1785              : 
    1786            0 :     Fingering* f = Factory::createFingering(note);
    1787              : 
    1788            0 :     f->setPlainText(String::number(note->string() + 1));
    1789            0 :     f->setTextStyleType(TextStyleType::STRING_NUMBER);
    1790            0 :     f->setFrameType(FrameType::CIRCLE);
    1791            0 :     note->add(f);
    1792              : }
    1793              : 
    1794         2030 : void GPConverter::addTrill(const GPNote* gpnote, Note* note)
    1795              : {
    1796              :     UNUSED(note);
    1797         2030 :     if (gpnote->trill().auxillaryFret == -1) {
    1798         2028 :         return;
    1799              :     }
    1800              : 
    1801            2 :     m_currentGPBeat->setTrill(true);
    1802              : }
    1803              : 
    1804         2095 : void GPConverter::addTrill(const GPBeat* gpbeat, ChordRest* cr)
    1805              : {
    1806         4190 :     m_continiousElementsBuilder->buildContiniousElement(cr, ElementType::TRILL, ContiniousElementsBuilder::ImportType::TRILL,
    1807         2095 :                                                         gpbeat->trill());
    1808         2095 : }
    1809              : 
    1810         2030 : void GPConverter::addOrnament(const GPNote* gpnote, Note* note)
    1811              : {
    1812         2030 :     if (gpnote->ornament() == GPNote::Ornament::None) {
    1813         2022 :         return;
    1814              :     }
    1815              : 
    1816            8 :     auto scoreOrnament = [](const auto& orn) {
    1817            8 :         if (orn == GPNote::Ornament::Turn) {
    1818            2 :             return SymId::ornamentTurn;
    1819            6 :         } else if (orn == GPNote::Ornament::InvertedTurn) {
    1820            2 :             return SymId::ornamentTurnInverted;
    1821            4 :         } else if (orn == GPNote::Ornament::LowerMordent) {
    1822            2 :             return SymId::ornamentMordent;
    1823            2 :         } else if (orn == GPNote::Ornament::UpperMordent) {
    1824            2 :             return SymId::ornamentShortTrill;
    1825              :         }
    1826            0 :         return SymId::ornamentUpPrall;
    1827              :     };
    1828              : 
    1829            8 :     Articulation* art = mu::engraving::Factory::createArticulation(_score->dummy());
    1830            8 :     art->setSymId(scoreOrnament(gpnote->ornament()));
    1831            8 :     if (!EditChord::toggleArticulation(_score, note, art)) {
    1832            0 :         delete art;
    1833              :     }
    1834              : }
    1835              : 
    1836         2030 : void GPConverter::addVibratoLeftHand(const GPNote* gpnote, Note*)
    1837              : {
    1838         2030 :     if (gpnote->vibratoType() == GPNote::VibratoType::None) {
    1839         2021 :         return;
    1840              :     }
    1841              : 
    1842            9 :     m_currentGPBeat->setVibratoLeftHand(
    1843            9 :         gpnote->vibratoType() == GPNote::VibratoType::Slight ? GPBeat::VibratoLeftHand::Slight : GPBeat::VibratoLeftHand::Wide);
    1844              : }
    1845              : 
    1846         2030 : Note* GPConverter::addHarmonic(const GPNote* gpnote, Note* note)
    1847              : {
    1848         2030 :     if (gpnote->harmonic().type == GPNote::Harmonic::Type::None) {
    1849         1981 :         return nullptr;
    1850              :     }
    1851              : 
    1852           49 :     Note* hnote = nullptr;
    1853           49 :     if (gpnote->harmonic().type != GPNote::Harmonic::Type::Natural) {
    1854           46 :         hnote = mu::engraving::Factory::createNote(note->chord());
    1855           46 :         hnote->setTrack(note->track());
    1856           46 :         hnote->setString(note->string());
    1857           46 :         hnote->setPitch(note->pitch());
    1858           46 :         hnote->setFret(note->fret());
    1859              : 
    1860              :         /// @note option to show or not additional harmonic fret in "<>" to be implemented
    1861              :         ///note->setDisplayFret(Note::DisplayFretOption::ArtificialHarmonic);
    1862              :         ///hnote->setDisplayFret(Note::DisplayFretOption::Hide);
    1863           46 :         hnote->setDisplayFret(Note::DisplayFretOption::Hide);
    1864              : 
    1865           46 :         hnote->setTpcFromPitch();
    1866           46 :         note->chord()->add(hnote);
    1867           46 :         hnote->setPlay(false);
    1868           46 :         note->setPlay(true);
    1869              : 
    1870           46 :         note->setHarmonicFret(note->fret() + gpnote->harmonic().fret);
    1871              :     } else {
    1872            3 :         note->setHarmonicFret(gpnote->harmonic().fret);
    1873            3 :         note->setDisplayFret(Note::DisplayFretOption::NaturalHarmonic);
    1874              :     }
    1875              : 
    1876           49 :     Note* harmonicNote = hnote ? hnote : note;
    1877              : 
    1878           49 :     int gproHarmonicType = static_cast<int>(gpnote->harmonic().type);
    1879           49 :     int harmonicFret = utils::harmonicOvertone(note, gpnote->harmonic().fret, gproHarmonicType);
    1880           49 :     int string = harmonicNote->string();
    1881           49 :     int harmonicPitch = harmonicNote->part()->instrument()->stringData()->getPitch(string,
    1882           49 :                                                                                    harmonicFret + capoFret(harmonicNote->part()),
    1883           49 :                                                                                    harmonicNote->staff());
    1884              : 
    1885           49 :     harmonicNote->setPitch(harmonicPitch);
    1886           49 :     harmonicNote->setTpcFromPitch();
    1887           49 :     harmonicNote->setHarmonic(true);
    1888           49 :     note->setHarmonicPitchOffset(harmonicNote->pitch() - note->pitch());
    1889              : 
    1890           49 :     if (GPNote::Harmonic::isArtificial(gpnote->harmonic().type) && m_currentGPBeat) {
    1891           46 :         m_currentGPBeat->addHarmonicMarkType(harmonicTypeNoteToBeat(gpnote->harmonic().type));
    1892              :     }
    1893              : 
    1894           49 :     return harmonicNote;
    1895              : }
    1896              : 
    1897         2030 : void GPConverter::addAccent(const GPNote* gpnote, Note* note)
    1898              : {
    1899         2030 :     if (gpnote->accents().none()) {
    1900         2024 :         return;
    1901              :     }
    1902              : 
    1903            6 :     auto symbolsIds = note->chord()->articulationSymbolIds();
    1904              : 
    1905           12 :     auto accentType = [](size_t flagIdx) {
    1906           12 :         if (flagIdx == 0) {
    1907            0 :             return SymId::articStaccatoAbove;
    1908           12 :         } else if (flagIdx == 2) {
    1909            4 :             return SymId::articMarcatoAbove;
    1910            8 :         } else if (flagIdx == 3) {
    1911            8 :             return SymId::articAccentAbove;
    1912              :         } else {
    1913            0 :             return SymId::dynamicSforzando;
    1914              :         }
    1915              :     };
    1916              : 
    1917           30 :     for (size_t flagIdx = 0; flagIdx < gpnote->accents().size(); flagIdx++) {
    1918           24 :         if (gpnote->accents()[flagIdx] && symbolsIds.find(accentType(flagIdx)) == symbolsIds.end()) {
    1919            6 :             Articulation* art = mu::engraving::Factory::createArticulation(note->chord());
    1920            6 :             art->setSymId(accentType(flagIdx));
    1921            6 :             note->chord()->add(art);
    1922              :         }
    1923              :     }
    1924            6 : }
    1925              : 
    1926         2030 : void GPConverter::addLeftHandTapping(const GPNote* gpnote)
    1927              : {
    1928         2030 :     if (gpnote->leftHandTapped() && m_currentGPBeat) {
    1929            0 :         m_currentGPBeat->setTappingHand(GPBeat::TappingHand::Left);
    1930              :     }
    1931         2030 : }
    1932              : 
    1933         2030 : void GPConverter::addRightHandTapping(const GPNote* gpnote)
    1934              : {
    1935         2030 :     if (gpnote->rightHandTapping() && m_currentGPBeat) {
    1936            2 :         m_currentGPBeat->setTappingHand(GPBeat::TappingHand::Right);
    1937              :     }
    1938         2030 : }
    1939              : 
    1940         2030 : void GPConverter::addSlide(const GPNote* gpnote, Note* note)
    1941              : {
    1942         2030 :     if (gpnote->slides().none()) {
    1943         1986 :         return;
    1944              :     }
    1945              : 
    1946           44 :     addSingleSlide(gpnote, note);
    1947           44 :     collectContinuousSlide(gpnote, note);
    1948              : }
    1949              : 
    1950           44 : void GPConverter::addSingleSlide(const GPNote* gpnote, Note* note)
    1951              : {
    1952           32 :     auto slideType = [](size_t flagIdx) -> ChordLineType {
    1953           32 :         switch (flagIdx) {
    1954            8 :         case 2:
    1955            8 :             return ChordLineType::FALL;
    1956            8 :         case 3:
    1957            8 :             return ChordLineType::DOIT;
    1958            8 :         case 4:
    1959            8 :             return ChordLineType::SCOOP;
    1960            8 :         case 5:
    1961            8 :             return ChordLineType::PLOP;
    1962            0 :         default:
    1963            0 :             LOGE() << "wrong slide type";
    1964            0 :             return ChordLineType::NOTYPE;
    1965              :         }
    1966              :     };
    1967              : 
    1968          220 :     for (size_t flagIdx = 2; flagIdx < gpnote->slides().size(); flagIdx++) {
    1969          176 :         if (gpnote->slides()[flagIdx]) {
    1970           32 :             ChordLine* cl = Factory::createChordLine(note->chord());
    1971           32 :             cl->setChordLineType(slideType(flagIdx));
    1972           32 :             cl->setStraight(true);
    1973           32 :             note->chord()->add(cl);
    1974           32 :             cl->setNote(note);
    1975              :         }
    1976              :     }
    1977           44 : }
    1978              : 
    1979           44 : void GPConverter::collectContinuousSlide(const GPNote* gpnote, Note* note)
    1980              : {
    1981           44 :     if (gpnote->slides()[0]) {
    1982            4 :         _slideHammerOnMap.push_back(std::pair(note, SlideHammerOn::Slide));
    1983              :     }
    1984           44 :     if (gpnote->slides()[1]) {
    1985            8 :         _slideHammerOnMap.push_back(std::pair(note, SlideHammerOn::LegatoSlide));
    1986              :     }
    1987           44 : }
    1988              : 
    1989         2030 : void GPConverter::addPickScrape(const GPNote* gpnote, Note* note)
    1990              : {
    1991         2030 :     if (gpnote->pickScrape() != GPNote::PickScrape::None && m_currentGPBeat) {
    1992            3 :         if (engravingConfiguration()->guitarProImportExperimental()) {
    1993            0 :             ChordLine* cl = mu::engraving::Factory::createChordLine(note->chord());
    1994            0 :             cl->setChordLineType(gpnote->pickScrape() == GPNote::PickScrape::Down ? ChordLineType::FALL : ChordLineType::DOIT);
    1995            0 :             cl->setWavy(true);
    1996            0 :             note->chord()->add(cl);
    1997            0 :             cl->setNote(note);
    1998              :         }
    1999              : 
    2000            3 :         m_currentGPBeat->setPickScrape(true);
    2001              :     }
    2002         2030 : }
    2003              : 
    2004         2030 : void GPConverter::collectHammerOn(const GPNote* gpnote, Note* note)
    2005              : {
    2006         2030 :     if (gpnote->hammerOn() == GPNote::HammerOn::Start) {
    2007           41 :         _slideHammerOnMap.push_back(std::pair(note, SlideHammerOn::HammerOn));
    2008              :     }
    2009         2030 : }
    2010              : 
    2011          185 : static mu::engraving::PitchValues gpBendCurveToPitchValues(const GPNote::Bend& b)
    2012              : {
    2013              :     using namespace mu::engraving;
    2014              : 
    2015          655 :     auto gpTimeToMuTime = [] (float time) {
    2016          655 :         return time * PitchValue::MAX_TIME / 100;
    2017              :     };
    2018              : 
    2019              :     //! NOTE: In GPX format, -1 means "not set". Normalize to sensible defaults.
    2020          185 :     const float originOffset = std::max(0.f, b.originOffset);
    2021          185 :     const float destOffset = std::max(0.f, b.destinationOffset);
    2022          185 :     const bool hasMiddleValue = (b.middleValue != -1) && !(b.middleOffset1 == 12 && b.middleOffset2 == 12);
    2023              : 
    2024          185 :     PitchValues pitchValues;
    2025              : 
    2026          185 :     pitchValues.push_back(PitchValue(gpTimeToMuTime(originOffset), b.originValue));
    2027          185 :     PitchValue lastPoint = pitchValues.back();
    2028              : 
    2029          185 :     if (hasMiddleValue) {
    2030          142 :         if (PitchValue value(gpTimeToMuTime(b.middleOffset1), b.middleValue);
    2031          142 :             b.middleOffset1 >= 0 && b.middleOffset1 < destOffset && value != lastPoint) {
    2032          132 :             pitchValues.push_back(std::move(value));
    2033              :         }
    2034              : 
    2035          142 :         if (PitchValue value(gpTimeToMuTime(b.middleOffset2), b.middleValue);
    2036          141 :             b.middleOffset2 >= 0 && b.middleOffset2 != b.middleOffset1
    2037           27 :             && b.middleOffset2 < destOffset
    2038          283 :             && value != lastPoint) {
    2039           25 :             pitchValues.push_back(std::move(value));
    2040              :         }
    2041              : 
    2042          142 :         if (b.middleOffset1 == -1 && b.middleOffset2 == -1 && b.middleValue != -1) {
    2043              :             //!@NOTE It seems when middle point is places exactly in the middle
    2044              :             //!of bend  GP6 stores this value equal -1
    2045            1 :             if (destOffset > 50) {
    2046            0 :                 pitchValues.push_back(PitchValue(gpTimeToMuTime(50), b.middleValue));
    2047              :             }
    2048              :         }
    2049              :     }
    2050              : 
    2051          185 :     if (b.destinationOffset <= 0) {
    2052            9 :         if (hasMiddleValue) {
    2053            1 :             PitchValue fixGpxValue = PitchValue(gpTimeToMuTime(50), b.middleValue);
    2054            1 :             if (b.middleValue > b.destinationValue && pitchValues.back() != fixGpxValue) {
    2055            1 :                 pitchValues.push_back(fixGpxValue);
    2056              :             }
    2057              :         }
    2058            9 :         pitchValues.push_back(PitchValue(gpTimeToMuTime(100), b.destinationValue)); //! In .gpx this value might be exist
    2059              :     } else {
    2060          176 :         if (PitchValue value(gpTimeToMuTime(destOffset), b.destinationValue); value != pitchValues.back()) {
    2061          176 :             pitchValues.push_back(std::move(value));
    2062              :         }
    2063              :     }
    2064              : 
    2065          185 :     return pitchValues;
    2066            0 : }
    2067              : 
    2068         2030 : void GPConverter::addBend(const GPNote* gpnote, Note* note)
    2069              : {
    2070         2030 :     if (!gpnote->bend() || gpnote->bend()->isEmpty()) {
    2071         1931 :         return;
    2072              :     }
    2073              : 
    2074              :     using namespace mu::engraving;
    2075              : 
    2076          101 :     PitchValues pitchValues = gpBendCurveToPitchValues(*gpnote->bend());
    2077              : 
    2078          101 :     if (pitchValues.size() < 2) {
    2079            0 :         return;
    2080              :     }
    2081              : 
    2082              :     /// not adding "hold" on 0 pitch
    2083          101 :     int maxPitch = (std::max_element(pitchValues.begin(), pitchValues.end(), [](const PitchValue& l, const PitchValue& r) {
    2084          174 :         return l.pitch < r.pitch;
    2085          101 :     }))->pitch;
    2086              : 
    2087          101 :     if (maxPitch == 0) {
    2088            2 :         return;
    2089              :     }
    2090              : 
    2091           99 :     m_guitarBendImporter->collectBend(note, pitchValues);
    2092          101 : }
    2093              : 
    2094         2030 : void GPConverter::setPitch(Note* note, const GPNote::MidiPitch& midiPitch)
    2095              : {
    2096         2030 :     int32_t fret = midiPitch.fret;
    2097         2030 :     int32_t musescoreString{ -1 };
    2098         2030 :     if (midiPitch.string != -1) {
    2099         2019 :         musescoreString = static_cast<int32_t>(note->part()->instrument()->stringData()->strings()) - 1 - midiPitch.string;
    2100              :     }
    2101              : 
    2102         2030 :     int pitch = 0;
    2103         2030 :     if (midiPitch.midi != -1) {
    2104         1177 :         pitch = midiPitch.midi;
    2105          853 :     } else if (midiPitch.octave != -1 || midiPitch.tone != 0) {
    2106           11 :         pitch = midiPitch.octave * 12 + midiPitch.tone;
    2107          842 :     } else if (midiPitch.variation != -1) {
    2108            0 :         pitch = calculateDrumPitch(midiPitch.element, midiPitch.variation, note->part()->shortName());
    2109          842 :     } else if (note->part()->midiChannel() == PERC_CHANNEL) {
    2110              :         //!@NOTE This is a case, when part of the note is a
    2111              :         //       single drum instrument. It seems, that GP
    2112              :         //       sets to -1 all midi parameters for the note,
    2113              :         //       but sets the midi pitch value to the program
    2114              :         //       instead.
    2115            0 :         pitch = note->part()->instrument()->channel(0)->program();
    2116              :     } else {
    2117          842 :         if (stringDatas.empty()) {
    2118            0 :             pitch = note->part()->instrument()->stringData()->getPitch(musescoreString, midiPitch.fret + capoFret(note->part()),
    2119            0 :                                                                        nullptr) + note->part()->instrument()->transpose().chromatic;
    2120              :         } else {
    2121          842 :             if (const auto sd = stringDatas.find(note->part()->id().toUint64()); sd != stringDatas.end()) {
    2122          842 :                 pitch = sd->second.getPitch(musescoreString, midiPitch.fret + capoFret(note->part()),
    2123          842 :                                             nullptr) + note->part()->instrument()->transpose().chromatic;
    2124              :             } else {
    2125            0 :                 pitch = note->part()->instrument()->stringData()->getPitch(musescoreString, midiPitch.fret + capoFret(note->part()),
    2126            0 :                                                                            nullptr) + note->part()->instrument()->transpose().chromatic;
    2127              :             }
    2128              :         }
    2129              :     }
    2130              : 
    2131         2030 :     pitch = std::clamp(pitch, 0, 127);
    2132              : 
    2133         2030 :     if (musescoreString == -1) {
    2134           11 :         musescoreString = getStringNumberFor(note, pitch);
    2135              : 
    2136           11 :         fret = note->part()->instrument()->stringData()->fret(pitch, musescoreString, nullptr);
    2137              :     }
    2138              : 
    2139         2030 :     bool hasDrumStaff = note->part()->hasDrumStaff();
    2140         2030 :     if (!engravingConfiguration()->guitarProImportExperimental() && hasDrumStaff) {
    2141           64 :         auto it = _drumExtension.find(pitch);
    2142           64 :         if (it != _drumExtension.end()) {
    2143            0 :             pitch =  it->second;
    2144              :         }
    2145              :     }
    2146              : 
    2147         2030 :     note->setFret(fret);
    2148              : 
    2149         2030 :     if (note->part()->instrument(note->tick())->useDrumset()) {
    2150           64 :         note->setString(0);
    2151              :     } else {
    2152         1966 :         note->setString(musescoreString);
    2153              :     }
    2154              : 
    2155         2030 :     note->setPitch(pitch);
    2156         2030 : }
    2157              : 
    2158         2030 : void GPConverter::setTpc(Note* note, int accidental)
    2159              : {
    2160         2030 :     if (0 == accidental || accidental == GPNote::invalidAccidental) {
    2161         1919 :         note->setTpcFromPitch();
    2162              :     } else {
    2163          111 :         note->setTpcFromPitch(accidental < 0 ? Prefer::FLATS : Prefer::SHARPS);
    2164              :     }
    2165         2030 : }
    2166              : 
    2167            0 : int GPConverter::calculateDrumPitch(int element, int variation, const String& instrumentName)
    2168              : {
    2169            0 :     return _drumResolver->pitch(element, variation, instrumentName);
    2170              : }
    2171              : 
    2172         2095 : void GPConverter::addDynamic(const GPBeat* gpb, ChordRest* cr)
    2173              : {
    2174         2095 :     if (!cr->isChord()) {
    2175         1805 :         return;
    2176              :     }
    2177              : 
    2178         1595 :     if (_dynamics.count(cr->track())) {
    2179         1343 :         if (_dynamics.at(cr->track()) == gpb->dynamic()) {
    2180         1305 :             return;
    2181              :         }
    2182              :     }
    2183              : 
    2184          290 :     auto convertDynamic = [](GPBeat::DynamicType t) {
    2185          290 :         if (t == GPBeat::DynamicType::FFF) {
    2186            4 :             return u"fff";
    2187          286 :         } else if (t == GPBeat::DynamicType::FF) {
    2188            5 :             return u"ff";
    2189          281 :         } else if (t == GPBeat::DynamicType::FF) {
    2190            0 :             return u"ff";
    2191          281 :         } else if (t == GPBeat::DynamicType::F) {
    2192           66 :             return u"f";
    2193          215 :         } else if (t == GPBeat::DynamicType::MF) {
    2194          193 :             return u"mf";
    2195           22 :         } else if (t == GPBeat::DynamicType::MP) {
    2196           14 :             return u"mp";
    2197            8 :         } else if (t == GPBeat::DynamicType::P) {
    2198            2 :             return u"p";
    2199            6 :         } else if (t == GPBeat::DynamicType::PP) {
    2200            4 :             return u"pp";
    2201              :         }
    2202            2 :         return u"ppp";
    2203              :     };
    2204              : 
    2205          290 :     Dynamic* dynamic = Factory::createDynamic(cr->segment());
    2206          290 :     dynamic->setTrack(cr->track());
    2207          290 :     dynamic->setDynamicType(convertDynamic(gpb->dynamic()));
    2208          290 :     cr->segment()->add(dynamic);
    2209          290 :     _dynamics[cr->track()] = gpb->dynamic();
    2210              : }
    2211              : 
    2212         2079 : void GPConverter::addTie(const GPNote* gpnote, Note* note, TieMap& ties)
    2213              : {
    2214         2079 :     if (gpnote->tieType() == GPNote::TieType::None) {
    2215         1913 :         return;
    2216              :     }
    2217              : 
    2218          102 :     auto startTie = [](Note* startNote, TieMap& ties, track_idx_t curTrack) {
    2219          102 :         Tie* tie = Factory::createTie(startNote);
    2220          102 :         startNote->add(tie);
    2221          102 :         ties[curTrack].push_back(tie);
    2222          102 :     };
    2223              : 
    2224          102 :     auto endTie = [this](Note* endNote, TieMap& ties, track_idx_t curTrack) {
    2225          102 :         auto& tiesOnTrack = ties[curTrack];
    2226          150 :         for (auto it = tiesOnTrack.rbegin(); it != tiesOnTrack.rend(); it++) {
    2227          150 :             Tie* tie = *it;
    2228          150 :             Note* startNote = tie->startNote();
    2229          150 :             int startPitch = startNote->pitch();
    2230          150 :             if (m_originalPitches.find(startNote) != m_originalPitches.end()) {
    2231            4 :                 startPitch = m_originalPitches[startNote];
    2232            4 :                 m_originalPitches.erase(startNote);
    2233              :             }
    2234              : 
    2235          150 :             if (startPitch == endNote->pitch() && startNote->string() == endNote->string()) {
    2236          102 :                 tie->setEndNote(endNote);
    2237          102 :                 endNote->setTieBack(tie);
    2238          102 :                 muse::remove(tiesOnTrack, tie);
    2239              : 
    2240              :                 /// adding tremolos to tied note
    2241          102 :                 Chord* startChord = toChord(startNote->parent());
    2242          102 :                 Chord* endChord = toChord(endNote->parent());
    2243          102 :                 if (m_tremolosInChords.find(startChord) != m_tremolosInChords.end()) {
    2244            0 :                     TremoloType type = m_tremolosInChords.at(startChord);
    2245            0 :                     DO_ASSERT(!isTremoloTwoChord(type));
    2246            0 :                     TremoloSingleChord* t = Factory::createTremoloSingleChord(endChord);
    2247            0 :                     t->setTremoloType(type);
    2248            0 :                     endChord->add(t);
    2249            0 :                     muse::remove(m_tremolosInChords, startChord);
    2250            0 :                     m_tremolosInChords[endChord] = type;
    2251              :                 }
    2252              : 
    2253          102 :                 break;
    2254              :             }
    2255              :         }
    2256          102 :     };
    2257              : 
    2258          166 :     if (gpnote->tieType() == GPNote::TieType::Start) {
    2259           64 :         startTie(note, ties, note->track());
    2260          102 :     } else if (gpnote->tieType() == GPNote::TieType::Mediate) {
    2261           38 :         endTie(note, ties, note->track());
    2262           38 :         startTie(note, ties, note->track());
    2263           64 :     } else if (gpnote->tieType() == GPNote::TieType::End) {
    2264           64 :         endTie(note, ties, note->track());
    2265              :     }
    2266              : }
    2267              : 
    2268         2131 : void GPConverter::addLegato(const GPBeat* beat, ChordRest* cr)
    2269              : {
    2270         2131 :     if (beat->legatoType() == GPBeat::LegatoType::None) {
    2271         2063 :         return;
    2272              :     }
    2273              : 
    2274              :     using slurMap = std::unordered_map<track_idx_t, Slur*>;
    2275              : 
    2276           22 :     auto startSlur = [](ChordRest* cr, Score* sc, slurMap& slurs, track_idx_t curTrack, Fraction curTick) {
    2277           44 :         if (auto it = slurs.find(curTrack); it != std::end(slurs)) {
    2278            8 :             slurs.erase(it);
    2279              :         }
    2280              : 
    2281           22 :         Slur* slur = Factory::createSlur(sc->dummy());
    2282           22 :         slur->setStartElement(cr);
    2283           22 :         slur->setTrack(curTrack);
    2284           22 :         slur->setTick(curTick);
    2285           22 :         slurs[curTrack] = slur;
    2286           22 :         sc->addSpanner(slur);
    2287           22 :     };
    2288              : 
    2289           30 :     auto mediateSlur = [](ChordRest* cr, slurMap& slurs, track_idx_t curTrack, Fraction curTick) {
    2290           30 :         Slur* slur = slurs[curTrack];
    2291           30 :         if (!slur) {
    2292            0 :             return;
    2293              :         }
    2294           30 :         slur->setTrack(curTrack);
    2295           30 :         slur->setTrack2(curTrack);
    2296           30 :         slur->setTick2(curTick);
    2297           30 :         slur->setEndElement(cr);
    2298              :     };
    2299              : 
    2300           16 :     auto endSlur = [](ChordRest* cr, slurMap& slurs, track_idx_t curTrack, Fraction curTick) {
    2301           16 :         Slur* slur = slurs[curTrack];
    2302           16 :         if (!slur) {
    2303            0 :             return;
    2304              :         }
    2305           16 :         slur->setTrack2(curTrack);
    2306           16 :         slur->setTick2(curTick);
    2307           16 :         slur->setEndElement(cr);
    2308              :     };
    2309              : 
    2310           68 :     if (beat->legatoType() == GPBeat::LegatoType::Start) {
    2311           22 :         startSlur(cr, _score, _slurs, cr->track(), cr->tick());
    2312           46 :     } else if (beat->legatoType() == GPBeat::LegatoType::Mediate) {
    2313           30 :         mediateSlur(cr, _slurs, cr->track(), cr->tick());
    2314           16 :     } else if (beat->legatoType() == GPBeat::LegatoType::End) {
    2315           16 :         endSlur(cr, _slurs, cr->track(), cr->tick());
    2316              :     }
    2317              : }
    2318              : 
    2319         2095 : void GPConverter::addOttava(const GPBeat* gpb, ChordRest* cr)
    2320              : {
    2321         2095 :     GPBeat::OttavaType gpType = gpb->ottavaType();
    2322         2095 :     m_continiousElementsBuilder->buildContiniousElement(cr, ElementType::OTTAVA, ottavaToImportType(
    2323              :                                                             gpType), gpType != GPBeat::OttavaType::None);
    2324              : 
    2325         2095 :     if (!cr->isChord()) {
    2326         2035 :         return;
    2327              :     }
    2328              : 
    2329         1595 :     Chord* chord = toChord(cr);
    2330         1595 :     const auto& [foundOttava, muOttavaType] = ottavaType(gpType);
    2331         1595 :     if (!foundOttava) {
    2332         1535 :         return;
    2333              :     }
    2334              : 
    2335          120 :     for (mu::engraving::Note* note : chord->notes()) {
    2336           60 :         int pitch = note->pitch();
    2337           60 :         setPitchByOttavaType(note, muOttavaType);
    2338              : 
    2339              :         // pitch changed because of octave
    2340           60 :         if (pitch != note->pitch()) {
    2341           60 :             m_originalPitches[note] = pitch;
    2342              :         }
    2343              :     }
    2344              : }
    2345              : 
    2346         2030 : void GPConverter::addLetRing(const GPNote* gpnote, Note* note)
    2347              : {
    2348              :     UNUSED(note);
    2349         2030 :     if (gpnote->letRing() && m_currentGPBeat) {
    2350           11 :         m_currentGPBeat->setLetRing(true);
    2351              :     }
    2352         2030 : }
    2353              : 
    2354         2030 : void GPConverter::addPalmMute(const GPNote* gpnote, Note* /*note*/)
    2355              : {
    2356         2030 :     if (gpnote->palmMute() && m_currentGPBeat) {
    2357            4 :         m_currentGPBeat->setPalmMute(true);
    2358              :     }
    2359         2030 : }
    2360              : 
    2361         2095 : void GPConverter::addLetRing(const GPBeat* gpbeat, ChordRest* cr)
    2362              : {
    2363         4190 :     m_continiousElementsBuilder->buildContiniousElement(cr, ElementType::LET_RING, ContiniousElementsBuilder::ImportType::LET_RING,
    2364         2095 :                                                         gpbeat->letRing());
    2365         2095 : }
    2366              : 
    2367         2095 : void GPConverter::addPalmMute(const GPBeat* gpbeat, ChordRest* cr)
    2368              : {
    2369         4190 :     m_continiousElementsBuilder->buildContiniousElement(cr, ElementType::PALM_MUTE, ContiniousElementsBuilder::ImportType::PALM_MUTE,
    2370         2095 :                                                         gpbeat->palmMute());
    2371         2095 : }
    2372              : 
    2373         2095 : void GPConverter::addDive(const GPBeat* beat, ChordRest* cr)
    2374              : {
    2375         2095 :     if (!beat->hasWhammy() || !cr->isChord()) {
    2376         2010 :         return;
    2377              :     }
    2378              : 
    2379              :     //! GPX reuses the same GPBeat pointer for multiple beat positions — treat as hold.
    2380           85 :     const track_idx_t track = cr->track();
    2381           85 :     PitchValues pitchValues;
    2382           85 :     if (m_lastWhammyBeat[track] == beat && beat->whammy().destinationValue != 0) {
    2383            1 :         const float holdValue = beat->whammy().destinationValue;
    2384            1 :         pitchValues.push_back(PitchValue(0, holdValue));
    2385            1 :         pitchValues.push_back(PitchValue(PitchValue::MAX_TIME, holdValue));
    2386              :     } else {
    2387           84 :         pitchValues = gpBendCurveToPitchValues(beat->whammy());
    2388              :     }
    2389           85 :     m_lastWhammyBeat[track] = beat;
    2390              : 
    2391           85 :     if (pitchValues.size() < 2) {
    2392            0 :         return;
    2393              :     }
    2394              : 
    2395           85 :     m_guitarBendImporter->collectDive(toChord(cr), pitchValues);
    2396           85 : }
    2397              : 
    2398         2095 : void GPConverter::addPickScrape(const GPBeat* beat, ChordRest* cr)
    2399              : {
    2400         4190 :     m_continiousElementsBuilder->buildContiniousElement(cr, ElementType::PICK_SCRAPE, ContiniousElementsBuilder::ImportType::PICK_SCRAPE,
    2401         2095 :                                                         beat->pickScrape());
    2402         2095 : }
    2403              : 
    2404         2095 : void GPConverter::addRasgueado(const GPBeat* beat, ChordRest* cr)
    2405              : {
    2406         4190 :     m_continiousElementsBuilder->buildContiniousElement(cr, ElementType::RASGUEADO, ContiniousElementsBuilder::ImportType::RASGUEADO,
    2407         2095 :                                                         beat->rasgueado() != GPBeat::Rasgueado::None);
    2408         2095 : }
    2409              : 
    2410         2095 : void GPConverter::addHarmonicMark(const GPBeat* gpbeat, ChordRest* cr)
    2411              : {
    2412         4190 :     m_continiousElementsBuilder->buildContiniousElement(cr, ElementType::HARMONIC_MARK,
    2413              :                                                         ContiniousElementsBuilder::ImportType::HARMONIC_ARTIFICIAL,
    2414         2095 :                                                         gpbeat->harmonicMarkArtificial(),
    2415              :                                                         ContiniousElementsBuilder::HarmonicMarkSubType::ARTIFICIAL);
    2416              : 
    2417         4190 :     m_continiousElementsBuilder->buildContiniousElement(cr, ElementType::HARMONIC_MARK,
    2418              :                                                         ContiniousElementsBuilder::ImportType::HARMONIC_PINCH,
    2419         2095 :                                                         gpbeat->harmonicMarkPinch(), ContiniousElementsBuilder::HarmonicMarkSubType::PINCH);
    2420              : 
    2421         4190 :     m_continiousElementsBuilder->buildContiniousElement(cr, ElementType::HARMONIC_MARK, ContiniousElementsBuilder::ImportType::HARMONIC_TAP,
    2422         2095 :                                                         gpbeat->harmonicMarkTap(), ContiniousElementsBuilder::HarmonicMarkSubType::TAP);
    2423              : 
    2424         4190 :     m_continiousElementsBuilder->buildContiniousElement(cr, ElementType::HARMONIC_MARK,
    2425              :                                                         ContiniousElementsBuilder::ImportType::HARMONIC_SEMI,
    2426         2095 :                                                         gpbeat->harmonicMarkSemi(), ContiniousElementsBuilder::HarmonicMarkSubType::SEMI);
    2427              : 
    2428         4190 :     m_continiousElementsBuilder->buildContiniousElement(cr, ElementType::HARMONIC_MARK,
    2429              :                                                         ContiniousElementsBuilder::ImportType::HARMONIC_FEEDBACK,
    2430         2095 :                                                         gpbeat->harmonicMarkFeedback(),
    2431              :                                                         ContiniousElementsBuilder::HarmonicMarkSubType::FEEDBACK);
    2432         2095 : }
    2433              : 
    2434         2095 : void GPConverter::addFretDiagram(const GPBeat* gpnote, ChordRest* cr, const Context& ctx, bool asHarmony)
    2435              : {
    2436         2095 :     int GPTrackIdx = static_cast<int>(muse::indexOf(_score->parts(), cr->part()));
    2437         2095 :     int diaId = gpnote->diagramIdx(GPTrackIdx, ctx.masterBarIndex);
    2438              : 
    2439         2095 :     if (_lastDiagramIdx == diaId) {
    2440         2095 :         return;
    2441              :     }
    2442              : 
    2443           23 :     _lastDiagramIdx = diaId;
    2444              : 
    2445           23 :     if (diaId == -1) {
    2446            8 :         return;
    2447              :     }
    2448              : 
    2449           15 :     auto trackIt = _gpDom->tracks().find(GPTrackIdx);
    2450           15 :     if (trackIt == _gpDom->tracks().cend()) {
    2451            0 :         return;
    2452              :     }
    2453              : 
    2454           15 :     if (trackIt->second->diagram().count(diaId) == 0) {
    2455            1 :         return;
    2456              :     }
    2457              : 
    2458           14 :     GPTrack::Diagram diagram = trackIt->second->diagram().at(diaId);
    2459              : 
    2460              :     /// currently importing fret diagrams as chord names
    2461           14 :     if (asHarmony) {
    2462           14 :         Harmony* h = Factory::createHarmony(cr->segment());
    2463           14 :         h->setTrack(cr->track());
    2464           14 :         h->setHarmonyType(HarmonyType::STANDARD);
    2465           14 :         h->setHarmony(diagram.name); // F#dim7
    2466           14 :         h->setPlainText(h->harmonyName());
    2467           14 :         cr->segment()->add(h);
    2468           14 :         return;
    2469              :     }
    2470              : 
    2471            0 :     FretDiagram* fretDiagram = mu::engraving::Factory::createFretDiagram(cr->segment());
    2472            0 :     fretDiagram->setTrack(cr->track());
    2473            0 :     fretDiagram->setStrings(diagram.stringCount);
    2474            0 :     fretDiagram->setFretOffset(diagram.baseFret);
    2475              : 
    2476            0 :     for (int st = 0; st < diagram.stringCount; st++) {
    2477            0 :         fretDiagram->setMarker(st, FretMarkerType::CROSS);
    2478              :     }
    2479              : 
    2480            0 :     for (const auto& fret: diagram.frets) {
    2481            0 :         if (fret.second == 0) {
    2482            0 :             fretDiagram->setMarker(fret.first, FretMarkerType::CIRCLE);
    2483              :         } else {
    2484            0 :             fretDiagram->setDot(fret.first, fret.second);
    2485              :         }
    2486              :     }
    2487              : 
    2488            0 :     cr->segment()->add(fretDiagram);
    2489           14 : }
    2490              : 
    2491         2095 : void GPConverter::addTapping(const GPBeat* beat, ChordRest* cr)
    2492              : {
    2493         2095 :     if (beat->tappingHand() == GPBeat::TappingHand::None || !cr->isChord()) {
    2494         2093 :         return;
    2495              :     }
    2496              : 
    2497            2 :     Chord* chord = toChord(cr);
    2498            2 :     Tapping* tapping = Factory::createTapping(chord);
    2499            2 :     tapping->setTrack(chord->track());
    2500            2 :     tapping->setHand(beat->tappingHand() == GPBeat::TappingHand::Left ? engraving::TappingHand::LEFT : engraving::TappingHand::RIGHT);
    2501            2 :     chord->add(tapping);
    2502              : }
    2503              : 
    2504         2095 : void GPConverter::addSlapped(const GPBeat* beat, ChordRest* cr)
    2505              : {
    2506         2095 :     if (!beat->slapped() || !cr->isChord()) {
    2507         2087 :         return;
    2508              :     }
    2509              : 
    2510            8 :     Articulation* art = mu::engraving::Factory::createArticulation(cr);
    2511            8 :     art->setTextType(ArticulationTextType::SLAP);
    2512            8 :     cr->add(art);
    2513              : }
    2514              : 
    2515         2095 : void GPConverter::addPopped(const GPBeat* beat, ChordRest* cr)
    2516              : {
    2517         2095 :     if (!beat->popped() || !cr->isChord()) {
    2518         2089 :         return;
    2519              :     }
    2520              : 
    2521            6 :     Articulation* art = mu::engraving::Factory::createArticulation(cr);
    2522            6 :     art->setTextType(ArticulationTextType::POP);
    2523            6 :     cr->add(art);
    2524              : }
    2525              : 
    2526         2095 : void GPConverter::addBrush(const GPBeat* beat, ChordRest* cr)
    2527              : {
    2528         2095 :     if (beat->brush() == GPBeat::Brush::None) {
    2529         2091 :         return;
    2530              :     }
    2531              : 
    2532            4 :     auto brushType = [](auto&& gpArp) {
    2533            4 :         if (gpArp == GPBeat::Brush::Up) {
    2534            2 :             return ArpeggioType::DOWN_STRAIGHT;
    2535              :         } else {
    2536            2 :             return ArpeggioType::UP_STRAIGHT;
    2537              :         }
    2538              :     };
    2539              : 
    2540            4 :     Arpeggio* arp = mu::engraving::Factory::createArpeggio(_score->dummy());
    2541            4 :     arp->setArpeggioType(brushType(beat->brush()));
    2542            4 :     arp->setStretch(beat->arpeggioStretch());
    2543              : 
    2544            4 :     cr->add(arp);
    2545              : }
    2546              : 
    2547         2095 : void GPConverter::addArpeggio(const GPBeat* beat, ChordRest* cr)
    2548              : {
    2549         2095 :     if (beat->arpeggio() == GPBeat::Arpeggio::None) {
    2550         2091 :         return;
    2551              :     }
    2552              : 
    2553            4 :     auto arpeggioType = [](auto&& gpArp) {
    2554            4 :         if (gpArp == GPBeat::Arpeggio::Up) {
    2555            2 :             return ArpeggioType::DOWN;
    2556              :         } else {
    2557            2 :             return ArpeggioType::UP;
    2558              :         }
    2559              :     };
    2560              : 
    2561            4 :     Arpeggio* arp = mu::engraving::Factory::createArpeggio(_score->dummy());
    2562            4 :     arp->setArpeggioType(arpeggioType(beat->arpeggio()));
    2563            4 :     arp->setStretch(beat->arpeggioStretch());
    2564            4 :     cr->add(arp);
    2565              : }
    2566              : 
    2567         2095 : void GPConverter::addTimer(const GPBeat* beat, ChordRest* cr)
    2568              : {
    2569         2095 :     if (beat->time() == -1) {
    2570         2089 :         return;
    2571              :     }
    2572              : 
    2573            6 :     int time = beat->time() / 1000;
    2574            6 :     int minutes = time / 60;
    2575            6 :     int seconds = time % 60;
    2576            6 :     StaffText* st = Factory::createStaffText(cr->segment());
    2577           18 :     st->setPlainText(String::number(minutes)
    2578           12 :                      + u':'
    2579           24 :                      + (seconds < 10 ? u'0' + String::number(seconds) : String::number(seconds)));
    2580            6 :     st->setTrack(cr->track());
    2581            6 :     cr->segment()->add(st);
    2582              : }
    2583              : 
    2584         2095 : void GPConverter::addFreeText(const GPBeat* beat, ChordRest* cr)
    2585              : {
    2586         2095 :     if (beat->freeText().isEmpty()) {
    2587         2088 :         return;
    2588              :     }
    2589              : 
    2590            7 :     auto text = Factory::createStaffText(cr->segment());
    2591            7 :     text->setTrack(cr->track());
    2592            7 :     text->setPlainText(beat->freeText());
    2593            7 :     cr->segment()->add(text);
    2594              : }
    2595              : 
    2596           12 : void GPConverter::setupTupletStyle(Tuplet* tuplet)
    2597              : {
    2598           12 :     bool real = false;
    2599              : 
    2600           12 :     switch (tuplet->ratio().numerator()) {
    2601            0 :     case 2: {
    2602            0 :         real = (tuplet->ratio().denominator() == 3);
    2603            0 :         break;
    2604              :     }
    2605           10 :     case 3:
    2606              :     case 4: {
    2607           10 :         real = ((tuplet->ratio().denominator() == 2) || (tuplet->ratio().denominator() == 6));
    2608           10 :         break;
    2609              :     }
    2610            1 :     case 5:
    2611              :     case 6:
    2612              :     case 7: {
    2613            1 :         real = (tuplet->ratio().denominator() == 4);
    2614            1 :         break;
    2615              :     }
    2616            0 :     case 9:
    2617              :     case 10:
    2618              :     case 11:
    2619              :     case 12:
    2620              :     case 13: {
    2621            0 :         real = (tuplet->ratio().denominator() == 8);
    2622            0 :         break;
    2623              :     }
    2624              :     }
    2625           12 :     if (!real) {
    2626            1 :         tuplet->setNumberType(TupletNumberType::SHOW_RELATION);
    2627            1 :         tuplet->setPropertyFlags(Pid::NUMBER_TYPE, PropertyFlags::UNSTYLED);
    2628              :     }
    2629           12 : }
    2630              : 
    2631           47 : bool GPConverter::tupletParamsChanged(const GPBeat* beat, const ChordRest* cr)
    2632              : {
    2633           47 :     return beat->tuplet().num == -1
    2634           41 :            || Fraction(beat->tuplet().num, beat->tuplet().denom) != m_nextTupletInfo.ratio
    2635           40 :            || cr->track() != m_nextTupletInfo.track
    2636           40 :            || cr->measure() != m_nextTupletInfo.measure
    2637          116 :            || (m_nextTupletInfo.elements.size() > 1
    2638           75 :                && m_nextTupletInfo.duration == Fraction(m_nextTupletInfo.ratio.denominator(), m_nextTupletInfo.lowestBase));
    2639              : }
    2640              : 
    2641         2095 : void GPConverter::addTuplet(const GPBeat* beat, ChordRest* cr)
    2642              : {
    2643         2095 :     Fraction currentTupletType = Fraction(beat->tuplet().num, beat->tuplet().denom);
    2644              : 
    2645         2095 :     if (m_nextTupletInfo.tuplet && tupletParamsChanged(beat, cr)) {
    2646            9 :         fillTuplet();
    2647              :     }
    2648              : 
    2649         2095 :     if (beat->tuplet().num == -1) {
    2650         2045 :         return;
    2651              :     }
    2652              : 
    2653           50 :     m_nextTupletInfo.lowestBase = std::min(m_nextTupletInfo.lowestBase, cr->ticks().denominator());
    2654              : 
    2655           50 :     if (!m_nextTupletInfo.tuplet) {
    2656           12 :         m_nextTupletInfo.tuplet  = Factory::createTuplet(_score->dummy());
    2657           12 :         m_nextTupletInfo.tuplet->setRatio(currentTupletType);
    2658           12 :         m_nextTupletInfo.ratio = currentTupletType;
    2659           12 :         m_nextTupletInfo.measure = cr->measure();
    2660           12 :         m_nextTupletInfo.track = cr->track();
    2661              :     }
    2662              : 
    2663           50 :     m_nextTupletInfo.elements.push_back(cr);
    2664           50 :     cr->setTuplet(m_nextTupletInfo.tuplet);
    2665           50 :     m_nextTupletInfo.duration += cr->actualTicks();
    2666              : }
    2667              : 
    2668         2095 : void GPConverter::addVibratoWTremBar(const GPBeat* beat, ChordRest* cr)
    2669              : {
    2670         4190 :     m_continiousElementsBuilder->buildContiniousElement(cr, ElementType::VIBRATO,
    2671              :                                                         ContiniousElementsBuilder::ImportType::VIBRATO_W_TREM_BAR_SLIGHT,
    2672         2095 :                                                         beat->vibratoWTremBar() == GPBeat::VibratoWTremBar::Slight,
    2673              :                                                         ContiniousElementsBuilder::VibratoSubType::W_TREM_BAR_SLIGHT);
    2674              : 
    2675         4190 :     m_continiousElementsBuilder->buildContiniousElement(cr, ElementType::VIBRATO,
    2676              :                                                         ContiniousElementsBuilder::ImportType::VIBRATO_W_TREM_BAR_WIDE,
    2677         2095 :                                                         beat->vibratoWTremBar() == GPBeat::VibratoWTremBar::Wide,
    2678              :                                                         ContiniousElementsBuilder::VibratoSubType::W_TREM_BAR_WIDE);
    2679         2095 : }
    2680              : 
    2681         2095 : void GPConverter::addVibratoLeftHand(const GPBeat* beat, ChordRest* cr)
    2682              : {
    2683         4190 :     m_continiousElementsBuilder->buildContiniousElement(cr, ElementType::VIBRATO,
    2684              :                                                         ContiniousElementsBuilder::ImportType::VIBRATO_LEFT_HAND_SLIGHT,
    2685         2095 :                                                         beat->vibratoLeftHand() == GPBeat::VibratoLeftHand::Slight,
    2686              :                                                         ContiniousElementsBuilder::VibratoSubType::LEFT_HAND_SLIGHT);
    2687              : 
    2688         4190 :     m_continiousElementsBuilder->buildContiniousElement(cr, ElementType::VIBRATO,
    2689              :                                                         ContiniousElementsBuilder::ImportType::VIBRATO_LEFT_HAND_WIDE,
    2690         2095 :                                                         beat->vibratoLeftHand() == GPBeat::VibratoLeftHand::Wide,
    2691              :                                                         ContiniousElementsBuilder::VibratoSubType::LEFT_HAND_WIDE);
    2692         2095 : }
    2693              : 
    2694         2095 : void GPConverter::addFadding(const GPBeat* beat, ChordRest* cr)
    2695              : {
    2696         2095 :     if (beat->fadding() == GPBeat::Fadding::None) {
    2697         2091 :         return;
    2698              :     }
    2699            7 :     if (!cr->isChord()) {
    2700            3 :         return;
    2701              :     }
    2702              : 
    2703            4 :     auto scoreFadding = [](const auto& fad) {
    2704            4 :         if (fad == GPBeat::Fadding::FadeIn) {
    2705            2 :             return SymId::guitarFadeIn;
    2706            2 :         } else if (fad == GPBeat::Fadding::FadeOut) {
    2707            0 :             return SymId::guitarFadeOut;
    2708              :         } else {
    2709            2 :             return SymId::guitarVolumeSwell;
    2710              :         }
    2711              :     };
    2712              : 
    2713            4 :     Articulation* art = mu::engraving::Factory::createArticulation(_score->dummy());
    2714            4 :     art->setSymId(scoreFadding(beat->fadding()));
    2715            4 :     if (!EditChord::toggleArticulation(_score, toChord(cr)->upNote(), art)) {
    2716            0 :         delete art;
    2717              :     }
    2718              : }
    2719              : 
    2720         2095 : void GPConverter::addHairPin(const GPBeat* beat, ChordRest* cr)
    2721              : {
    2722         4190 :     m_continiousElementsBuilder->buildContiniousElement(cr, ElementType::HAIRPIN, hairpinToImportType(beat->hairpin()),
    2723         2095 :                                                         beat->hairpin() != GPBeat::Hairpin::None);
    2724         2095 : }
    2725              : 
    2726         2095 : void GPConverter::addPickStroke(const GPBeat* beat, ChordRest* cr)
    2727              : {
    2728         2095 :     if (beat->pickStroke() == GPBeat::PickStroke::None) {
    2729         2091 :         return;
    2730              :     }
    2731            4 :     if (!cr->isChord()) {
    2732            0 :         return;
    2733              :     }
    2734              : 
    2735            4 :     auto scorePickStroke = [](const auto& p) {
    2736            4 :         if (p == GPBeat::PickStroke::Up) {
    2737            2 :             return SymId::stringsUpBow;
    2738              :         } else {
    2739            2 :             return SymId::stringsDownBow;
    2740              :         }
    2741              :     };
    2742              : 
    2743            4 :     Articulation* art = mu::engraving::Factory::createArticulation(_score->dummy());
    2744            4 :     art->setSymId(scorePickStroke(beat->pickStroke()));
    2745            4 :     if (!EditChord::toggleArticulation(_score, toChord(cr)->upNote(), art)) {
    2746            0 :         delete art;
    2747              :     }
    2748              : }
    2749              : 
    2750         2095 : void GPConverter::addTremolo(const GPBeat* beat, ChordRest* cr)
    2751              : {
    2752         2095 :     if (!cr->isChord() || beat->tremolo().numerator == -1) {
    2753         2089 :         return;
    2754              :     }
    2755              : 
    2756            6 :     auto scoreTremolo = [](const GPBeat::Tremolo tr) {
    2757            6 :         if (tr.denominator == 2) {
    2758            2 :             return TremoloType::R8;
    2759              :         }
    2760            4 :         if (tr.denominator == 4) {
    2761            2 :             return TremoloType::R16;
    2762              :         } else {
    2763            2 :             return TremoloType::R32;
    2764              :         }
    2765              :     };
    2766              : 
    2767            6 :     TremoloSingleChord* t = Factory::createTremoloSingleChord(_score->dummy());
    2768            6 :     t->setTremoloType(scoreTremolo(beat->tremolo()));
    2769            6 :     Chord* ch = toChord(cr);
    2770            6 :     ch->add(t);
    2771            6 :     m_tremolosInChords[ch] = t->tremoloType();
    2772              : }
    2773              : 
    2774         2095 : void GPConverter::addWah(const GPBeat* beat, ChordRest* cr)
    2775              : {
    2776         2095 :     if (beat->wah() == GPBeat::Wah::None) {
    2777         2091 :         return;
    2778              :     }
    2779            4 :     if (!cr->isChord()) {
    2780            0 :         return;
    2781              :     }
    2782              : 
    2783            4 :     auto scoreWah = [] (const auto& wah) {
    2784            4 :         if (wah == GPBeat::Wah::Open) {
    2785            2 :             return SymId::brassMuteOpen;
    2786              :         }
    2787            2 :         return SymId::brassMuteClosed;
    2788              :     };
    2789              : 
    2790            4 :     Articulation* art = Factory::createArticulation(_score->dummy());
    2791            4 :     art->setSymId(scoreWah(beat->wah()));
    2792            4 :     if (!EditChord::toggleArticulation(_score, toChord(cr)->upNote(), art)) {
    2793            0 :         delete art;
    2794              :     }
    2795              : }
    2796              : 
    2797         2095 : void GPConverter::addGolpe(const GPBeat* beat, ChordRest* cr)
    2798              : {
    2799         2095 :     if (beat->golpe() == GPBeat::Golpe::None) {
    2800         2095 :         return;
    2801              :     }
    2802            0 :     if (!cr->isChord()) {
    2803            0 :         return;
    2804              :     }
    2805              : 
    2806            0 :     Articulation* art = Factory::createArticulation(_score->dummy());
    2807            0 :     art->setSymId(SymId::guitarGolpe);
    2808              : 
    2809            0 :     if (beat->golpe() == GPBeat::Golpe::Thumb) {
    2810            0 :         art->setAnchor(ArticulationAnchor::BOTTOM);
    2811              :     }
    2812              : 
    2813            0 :     if (!EditChord::toggleArticulation(_score, toChord(cr)->upNote(), art)) {
    2814            0 :         delete art;
    2815              :     }
    2816              : }
    2817              : 
    2818         2095 : void GPConverter::addBarre(const GPBeat* beat, ChordRest* cr)
    2819              : {
    2820         2095 :     if (beat->barre().fret == -1) {
    2821         2091 :         return;
    2822              :     }
    2823            4 :     if (!cr->isChord()) {
    2824            0 :         return;
    2825              :     }
    2826              : 
    2827            4 :     auto barreType = [](const GPBeat::Barre& barre) {
    2828            4 :         if (barre.string == 1) {
    2829            4 :             return std::string("1/2B ");
    2830              :         } else {
    2831            4 :             return std::string("B ");
    2832              :         }
    2833              :     };
    2834              : 
    2835            4 :     std::string barreFret;
    2836            4 :     int fret = beat->barre().fret;
    2837              : 
    2838            6 :     for (int i = 0; i < (fret / 10); i++) {
    2839            2 :         barreFret += "X";
    2840              :     }
    2841            4 :     int targetMod10 = fret % 10;
    2842            4 :     if (targetMod10 == 9) {
    2843            0 :         barreFret += "IX";
    2844            4 :     } else if (targetMod10 == 4) {
    2845            0 :         barreFret += "IV";
    2846              :     } else {
    2847            4 :         if (targetMod10 >= 5) {
    2848            4 :             barreFret += "V";
    2849            4 :             targetMod10-=5;
    2850              :         }
    2851           10 :         for (int j = 0; j < targetMod10; j++) {
    2852            6 :             barreFret += "I";
    2853              :         }
    2854              :     }
    2855              : 
    2856            4 :     addTextToNote(String::fromStdString(barreType(beat->barre()) + barreFret), toChord(cr)->upNote());
    2857            4 : }
    2858              : 
    2859         2095 : void GPConverter::addLyrics(const GPBeat* beat, ChordRest* cr, const Context& ctx)
    2860              : {
    2861         2095 :     ID GPTrackIdx = cr->part()->id();
    2862              : 
    2863         2095 :     const std::string& lyrStr = beat->lyrics(GPTrackIdx.toUint64(), ctx.masterBarIndex);
    2864         2095 :     if (lyrStr.empty()) {
    2865         2095 :         return;
    2866              :     }
    2867              : 
    2868            0 :     Lyrics* lyr = Factory::createLyrics(_score->dummy());
    2869              : 
    2870            0 :     if (lyrStr.back() == '-') {
    2871            0 :         lyr->setSyllabic(LyricsSyllabic::MIDDLE);
    2872            0 :         lyr->setPlainText(String::fromUtf8(lyrStr.substr(0, lyrStr.size() - 1).c_str()));
    2873              :     } else {
    2874            0 :         lyr->setPlainText(String::fromUtf8(lyrStr.c_str()));
    2875              :     }
    2876            0 :     cr->add(lyr);
    2877              : }
    2878              : 
    2879          724 : void GPConverter::clearDefectedGraceChord(ChordRestContainer& graceGhords)
    2880              : {
    2881          724 :     for (auto [pCr, gpBeat] : graceGhords) {
    2882              :         UNUSED(gpBeat);
    2883              : 
    2884            0 :         if (!pCr) {
    2885            0 :             continue;
    2886              :         }
    2887              : 
    2888            0 :         if (pCr->isChord()) {
    2889            0 :             Chord* pChord = toChord(pCr);
    2890            0 :             for (Note* pNote : pChord->notes()) {
    2891            0 :                 auto it = _slideHammerOnMap.begin(), e = _slideHammerOnMap.end();
    2892            0 :                 for (; it != e; ++it) {
    2893            0 :                     if (it->first == pNote) {
    2894            0 :                         _slideHammerOnMap.erase(it);
    2895            0 :                         break;
    2896              :                     }
    2897              :                 }
    2898              :             }
    2899              : 
    2900            0 :             for (Chord* pGraceChord : pChord->graceNotes()) {
    2901            0 :                 for (Note* pNote : pGraceChord->notes()) {
    2902            0 :                     auto it = _slideHammerOnMap.begin(), e = _slideHammerOnMap.end();
    2903            0 :                     for (; it != e; ++it) {
    2904            0 :                         if (it->first == pNote) {
    2905            0 :                             _slideHammerOnMap.erase(it);
    2906            0 :                             break;
    2907              :                         }
    2908              :                     }
    2909              :                 }
    2910              :             }
    2911              :         }
    2912            0 :         delete pCr;
    2913              :     }
    2914          724 :     graceGhords.clear();
    2915          724 : }
    2916              : 
    2917            4 : void GPConverter::addTextToNote(muse::String string, Note* note)
    2918              : {
    2919            4 :     Segment* segment = note->chord()->segment();
    2920            4 :     StaffText* text = Factory::createStaffText(segment);
    2921              : 
    2922            4 :     if (!string.isEmpty()) {
    2923            4 :         bool useHarmony = string[string.size() - 1] == '\\';
    2924            4 :         if (useHarmony) {
    2925            0 :             string.chop(1);
    2926              :         }
    2927              :     }
    2928            4 :     text->setPlainText(string);
    2929            4 :     text->setTrack(note->chord()->track());
    2930            4 :     segment->add(text);
    2931            4 : }
    2932              : 
    2933          221 : void GPConverter::clearDefectedSpanner()
    2934              : {
    2935          262 :     for (const auto& [track, elems] : _ties) {
    2936           41 :         for (Tie* tie : elems) {
    2937            0 :             if (tie->startNote()) {
    2938            0 :                 tie->startNote()->setTieFor(nullptr);
    2939              :             }
    2940              : 
    2941            0 :             if (tie->endNote()) {
    2942            0 :                 tie->endNote()->setTieBack(nullptr);
    2943              :             }
    2944              : 
    2945            0 :             delete tie;
    2946              :         }
    2947              :     }
    2948          221 : }
    2949              : 
    2950           11 : int GPConverter::getStringNumberFor(mu::engraving::Note* pNote, int pitch) const
    2951              : {
    2952           11 :     const auto& stringTable = pNote->part()->instrument()->stringData()->stringList();
    2953              : 
    2954           11 :     const size_t stringTableSize = stringTable.size();
    2955              : 
    2956           11 :     if (!stringTableSize) {
    2957            0 :         return -1;
    2958              :     }
    2959              : 
    2960           11 :     const int32_t lastIdx = static_cast<int32_t>(stringTableSize) - 1;
    2961              : 
    2962           22 :     for (int32_t idx = lastIdx; idx >= 0; --idx) {
    2963           22 :         auto string = stringTable[idx];
    2964           22 :         const int32_t currenStringNumber = lastIdx - idx;
    2965              : 
    2966           22 :         if (pitch >= string.pitch) {
    2967           11 :             bool emptyString = true;
    2968              : 
    2969           22 :             for (const auto& noteTmp : pNote->chord()->notes()) {
    2970           11 :                 if (noteTmp->string() == currenStringNumber) {
    2971            0 :                     emptyString = false;
    2972            0 :                     break;
    2973              :                 }
    2974              :             }
    2975              : 
    2976           11 :             if (emptyString) {
    2977           11 :                 return currenStringNumber;
    2978              :             }
    2979              :         }
    2980              :     }
    2981              : 
    2982            0 :     return -1;
    2983              : }
    2984              : 
    2985         1595 : void GPConverter::setBeamMode(const GPBeat* beat, ChordRest* cr, Measure* measure, Fraction tick)
    2986              : {
    2987         1595 :     BeamMode beamMode = BeamMode::AUTO;
    2988              : 
    2989         1595 :     if (beat->beamMode() == GPBeat::BeamMode::BROKEN) {
    2990           11 :         beamMode = BeamMode::NONE;
    2991         1584 :     } else if (beat->beamMode() == GPBeat::BeamMode::JOINED) {
    2992           11 :         beamMode = BeamMode::MID;
    2993         1573 :     } else if (beat->beamMode() == GPBeat::BeamMode::BROKEN2 || beat->beamMode() == GPBeat::BeamMode::BROKEN2_JOINED) {
    2994            7 :         int measureDenom = measure->ticks().denominator();
    2995            7 :         double fract = (double)tick.numerator() / tick.denominator() * measureDenom;
    2996              : 
    2997            7 :         if ((int)fract == fract && beat->beamMode() != GPBeat::BeamMode::BROKEN2_JOINED) {
    2998              :             /// keep auto direction for some beams, so BEGIN16/BEGIN32 modes work properly
    2999              :             /// (forcing divide of beam groups, TODO-gp: make possible to show broken2 type from guitar pro
    3000            1 :             beamMode = BeamMode::AUTO;
    3001            6 :         } else if (cr->ticks() > Fraction(1, 32)) {
    3002            6 :             beamMode = BeamMode::BEGIN16;
    3003              :         } else {
    3004            0 :             beamMode = BeamMode::BEGIN32;
    3005              :         }
    3006              :     }
    3007              : 
    3008         1595 :     cr->setBeamMode(m_previousBeamMode);
    3009         1595 :     m_previousBeamMode = beamMode;
    3010         1595 : }
    3011              : 
    3012          221 : void GPConverter::addTuning()
    3013              : {
    3014          221 :     const Measure* m = _score->firstMeasure();
    3015              : 
    3016              :     // NOTE: GP doesn't support multiple tunings on one part
    3017              :     // We're safe to just take the very first chord rest segment
    3018              :     // and check if it has any non-standard tuning
    3019          221 :     const Fraction& f{ 0, 1 };
    3020              : 
    3021          460 :     for (auto p : _score->parts()) {
    3022          481 :         for (auto s : p->staves()) {
    3023          242 :             if (!s->isPrimaryStaff()) {
    3024          229 :                 continue;
    3025              :             }
    3026              : 
    3027          242 :             Segment* seg = m->findSegment(SegmentType::ChordRest, f);
    3028              : 
    3029          242 :             IF_ASSERT_FAILED(seg) {
    3030            0 :                 LOGE() << "First measure MUST has a chord rest segment after import";
    3031            0 :                 return;
    3032              :             }
    3033              : 
    3034          242 :             if (stringDatas.find(p->id().toUint64()) == stringDatas.end()) {
    3035            3 :                 continue;
    3036              :             }
    3037              : 
    3038          239 :             const StringData sd = stringDatas.at(p->id().toUint64());
    3039          239 :             std::vector<int> tuning(sd.strings());
    3040         1665 :             for (size_t i = 0; i < tuning.size(); ++i) {
    3041         1426 :                 tuning[i] = sd.stringList().at(i).pitch + p->instrument()->transpose().chromatic;
    3042              :             }
    3043              : 
    3044          239 :             if (utils::isStandardTuning(p->instrument()->channel(0)->program(), tuning)) {
    3045          226 :                 continue;
    3046              :             }
    3047              : 
    3048           13 :             StringTunings* tun = Factory::createStringTunings(seg);
    3049           13 :             tun->setStringData(sd);
    3050           13 :             tun->setTrack(staff2track(s->idx()));
    3051           13 :             seg->add(tun);
    3052          465 :         }
    3053              :     }
    3054              : }
    3055              : 
    3056          891 : int GPConverter::capoFret(const Part* part) const
    3057              : {
    3058          891 :     const auto it = m_capoParams.find(part->id().toUint64());
    3059          891 :     return it != m_capoParams.end() ? it->second : 0;
    3060              : }
    3061              : 
    3062          221 : void GPConverter::addCapos()
    3063              : {
    3064          221 :     const Measure* firstMeasure = _score->firstMeasure();
    3065          221 :     const size_t stavesCount = _score->staves().size();
    3066              : 
    3067          221 :     Segment* segment = firstMeasure->first(SegmentType::ChordRest);
    3068          463 :     for (size_t i = 0; i < stavesCount; ++i) {
    3069          242 :         Staff* staff = _score->staff(i);
    3070          242 :         const auto& it = m_capoParams.find(staff->part()->id().toUint64());
    3071              : 
    3072          242 :         if (it != m_capoParams.end() && it->second > 0) {
    3073            0 :             size_t track = i * VOICES;
    3074              : 
    3075            0 :             CapoParams params;
    3076            0 :             params.active = true;
    3077            0 :             params.transposeMode = CapoParams::TransposeMode::TAB_ONLY;
    3078            0 :             params.fretPosition = it->second;
    3079              : 
    3080            0 :             Capo* capo = Factory::createCapo(_score->dummy());
    3081            0 :             capo->setTrack(track);
    3082            0 :             capo->setParams(params);
    3083            0 :             segment->add(capo);
    3084              : 
    3085            0 :             staff->insertCapoParams({ 0, 1 }, params, true);
    3086            0 :         }
    3087              :     }
    3088          221 : }
    3089              : } // namespace mu::iex::guitarpro
        

Generated by: LCOV version 2.0-1