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

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

Generated by: LCOV version 2.0-1