//=============================================================================
//  MuseScore
//  Music Composition & Notation
//
//  Copyright (C) 2011 Werner Schweer
//
//  This program is free software; you can redistribute it and/or modify
//  it under the terms of the GNU General Public License version 2
//  as published by the Free Software Foundation and appearing in
//  the file LICENCE.GPL
//=============================================================================
 
#include "importgtp.h"
#include "globals.h"
#include "libmscore/score.h"
#include "libmscore/measurebase.h"
#include "libmscore/text.h"
#include "libmscore/box.h"
#include "libmscore/staff.h"
#include "libmscore/part.h"
#include "libmscore/measure.h"
#include "libmscore/timesig.h"
#include "libmscore/tremolo.h"
#include "libmscore/rest.h"
#include "libmscore/chord.h"
#include "libmscore/note.h"
#include "libmscore/stringdata.h"
#include "libmscore/clef.h"
#include "libmscore/lyrics.h"
#include "libmscore/tempotext.h"
#include "libmscore/slur.h"
#include "libmscore/tie.h"
#include "libmscore/tuplet.h"
#include "libmscore/barline.h"
#include "libmscore/excerpt.h"
#include "libmscore/stafftype.h"
#include "libmscore/bracket.h"
#include "libmscore/articulation.h"
#include "libmscore/keysig.h"
#include "libmscore/harmony.h"
#include "libmscore/bend.h"
#include "libmscore/tremolobar.h"
#include "libmscore/segment.h"
#include "libmscore/rehearsalmark.h"
#include "libmscore/dynamic.h"
#include "libmscore/arpeggio.h"
#include "libmscore/volta.h"
#include "libmscore/instrtemplate.h"
#include "libmscore/fingering.h"
#include "libmscore/notedot.h"
#include "libmscore/stafftext.h"
#include "libmscore/sym.h"
#include "preferences.h"
 
namespace Ms {
 
//---------------------------------------------------------
//   readMixChange
//---------------------------------------------------------
 
bool GuitarPro4::readMixChange(Measure* measure)
      {
      /*char patch   =*/ readChar();
      signed char volume  = readChar();
      signed char pan     = readChar();
      signed char chorus  = readChar();
      signed char reverb  = readChar();
      signed char phase   = readChar();
      signed char tremolo = readChar();
      int tempo    = readInt();
 
      bool tempoEdited = false;
 
      if (volume >= 0)
            readChar();
      if (pan >= 0)
            readChar();
      if (chorus >= 0)
            readChar();
      if (reverb >= 0)
            readChar();
      if (phase >= 0)
            readChar();
      if (tremolo >= 0)
            readChar();
      if (tempo >= 0) {
            if (tempo != previousTempo) {
                  previousTempo = tempo;
                  setTempo(tempo, measure);
                  }
            readChar();
            tempoEdited = true;
            }
 
      readChar();       // bitmask: what should be applied to all tracks
      return tempoEdited;
      }
 
//---------------------------------------------------------
//   readBeatEffects
//---------------------------------------------------------
 
int GuitarPro4::readBeatEffects(int track, Segment* segment)
      {
      int effects = 0;
      uchar fxBits1 = readUChar();
      uchar fxBits2 = readUChar();
      if (fxBits1 & BEAT_FADE)
            effects = 4; // fade in
      if (fxBits1 & BEAT_EFFECT) {
            effects = readUChar();      // effect 1-tapping, 2-slapping, 3-popping
            }
      if (fxBits2 & BEAT_TREMOLO)
            readTremoloBar(track,segment);
      if (fxBits1 & BEAT_ARPEGGIO) {
            int strokeup = readUChar();            // up stroke length
            int strokedown = readUChar();            // down stroke length
 
            Arpeggio* a = new Arpeggio(score);
            if( strokeup > 0 ) {
                  a->setArpeggioType(ArpeggioType::UP_STRAIGHT);
                  }
            else if( strokedown > 0 ) {
                  a->setArpeggioType(ArpeggioType::DOWN_STRAIGHT);
                  }
            else {
                  delete a;
                  a = 0;
                  }
 
            if(a) {
                  ChordRest* cr = new Chord(score);
                  cr->setTrack(track);
                  cr->add(a);
                  segment->add(cr);
                  }
            }
      if (fxBits2 & BEAT_STROKE_DIR) {
            effects = readUChar();            // stroke pick direction
            effects += 4;    //1 or 2 for effects becomes 4 or 5
            }
      if (fxBits1 & 0x01) {         // GP3 column-wide vibrato
            }
      if (fxBits1 & 0x2) {          // GP3 column-wide wide vibrato (="tremolo" in GP3)
            }
      return effects;
      }
 
//---------------------------------------------------------
//   readNote
//---------------------------------------------------------
 
bool GuitarPro4::readNote(int string, int staffIdx, Note* note)
      {
      uchar noteBits = readUChar();
 
      //
      // noteBits:
      //    7 - Right hand or left hand fingering;
      //    6 - Accentuated note
      //    5 - Note type (rest, empty note, normal note);
      //    4 - note dynamic;
      //    3 - Presence of effects linked to the note;
      //    2 - Ghost note;
      //    1 - Dotted note;  ?
      //    0 - Time-independent duration
 
      if (noteBits & BEAT_TREMOLO) {
            note->setHeadGroup(NoteHead::Group::HEAD_CROSS);
            note->setGhost(true);
            }
 
      bool tieNote = false;
      uchar variant = 1;
      if (noteBits & BEAT_EFFECT) {
            variant = readUChar();
            if (variant == 1) {     // normal note
                  }
            else if (variant == 2) {
                  /* guitar pro 4 bundles tied notes with slides in the representation
                   * we take note when we see ties and do not create slides for these notes. */
                  slides[staffIdx * VOICES] = -2;
                  tieNote = true;
                  }
            else if (variant == 3) {                 // dead notes = ghost note
                  note->setHeadGroup(NoteHead::Group::HEAD_CROSS);
                  note->setGhost(true);
                  }
            else
                  qDebug("unknown note variant: %d", variant);
            }
 
      if (noteBits & 0x1) {               // note != beat
            int a = readUChar();          // length
            int b = readUChar();          // t
            qDebug("          Time-independent note len, len %d t %d", a, b);
            }
      if (noteBits & 0x2) {               // note is dotted
            //readUChar();
            }
 
      // set dynamic information on note if different from previous note
      if (noteBits & NOTE_DYNAMIC) {
            int d = readChar();
            if (previousDynamic != d) {
                  previousDynamic = d;
                  addDynamic(note, d);
                  }
            }
 
      int fretNumber = -1;
      if (noteBits & NOTE_FRET)
            fretNumber = readUChar();
 
      // check if a note is supposed to be accented, and give it the sforzato type
      if (noteBits & NOTE_SFORZATO) {
            Articulation* art = new Articulation(note->score());
            art->setSymId(SymId::articAccentAbove);
            if (!note->score()->addArticulation(note, art))
                  delete art;
            }
 
      if (noteBits & NOTE_FINGERING) {
            int leftFinger = readUChar();
            int rightFinger = readUChar();
            Text* f = new Fingering(score);
            QString finger;
            // if there is a valid left hand fingering
            if (leftFinger < 5) {
                  if (leftFinger == 0)
                        finger = "T";
                  else if (leftFinger == 1)
                        finger = "1";
                  else if (leftFinger == 2)
                        finger = "2";
                  else if (leftFinger == 3)
                        finger = "3";
                  else if (leftFinger == 4)
                        finger = "4";
                  }
            else  {
                  if (rightFinger == 0)
                        finger = "T";
                  else if (rightFinger == 1)
                        finger = "I";
                  else if (rightFinger == 2)
                        finger = "M";
                  else if (rightFinger == 3)
                        finger = "A";
                  else if (rightFinger == 4)
                        finger = "O";
                  }
            f->setPlainText(finger);
            note->add(f);
            f->reset();
            }
      bool slur = false;
      if (noteBits & BEAT_EFFECTS) {
            uchar modMask1 = readUChar();
            uchar modMask2 = readUChar();
            if (modMask1 & EFFECT_BEND)
                  readBend(note);
            if (modMask1 & EFFECT_HAMMER)
                  slur = true;
            if (modMask1 & EFFECT_LET_RING)
                  addLetRing(note->chord(), note->staffIdx(), true);
            else
                  addLetRing(note->chord(), note->staffIdx(), false);
            if (modMask1 & EFFECT_GRACE) {
                  int fret = readUChar();            // grace fret
                  int dynamic = readUChar();            // grace dynamic
                  int transition = readUChar();            // grace transition
                  int duration = readUChar();            // grace duration
 
                  int grace_len = MScore::division/8;
                  if (duration == 1)
                        grace_len = MScore::division/8; //32th
                  else if (duration == 2)
                        grace_len = MScore::division/6; //24th
                  else if (duration == 3)
                        grace_len = MScore::division/4; //16th
 
                  Note* gn = new Note(score);
 
                  if (fret == 255) {
                        gn->setHeadGroup(NoteHead::Group::HEAD_CROSS);
                        gn->setGhost(true);
                        }
                  if (fret == 255)
                        fret = 0;
                  gn->setFret(fret);
                  gn->setString(string);
                  int grace_pitch = note->part()->instrument()->stringData()->getPitch(string, fret, nullptr, 0);
                  gn->setPitch(grace_pitch);
                  gn->setTpcFromPitch();
 
                  Chord* gc = new Chord(score);
                  gc->setTrack(note->chord()->track());
                  gc->add(gn);
                  gc->setParent(note->chord());
 
                  TDuration d;
                  d.setVal(grace_len);
                  if(grace_len == MScore::division/6)
                        d.setDots(1);
                  gc->setDurationType(d);
                  gc->setDuration(d.fraction());
                  gc->setNoteType(NoteType::ACCIACCATURA);
                  gc->setMag(note->chord()->staff()->mag(0) * score->styleD(StyleIdx::graceNoteMag));
                  note->chord()->add(gc);
                  addDynamic(gn, dynamic);
 
                  if (transition == 0) {
                        // no transition
                        }
                  else if(transition == 1){
                        //TODO: Add a 'slide' guitar effect when implemented
                        }
                  else if (transition == 2 && fretNumber>=0 && fretNumber<=255 && fretNumber!=gn->fret()) {
                        QList<PitchValue> points;
                        points.append(PitchValue(0,0, false));
                        points.append(PitchValue(60,(fretNumber-gn->fret())*100, false));
 
                        Bend* b = new Bend(note->score());
                        b->setPoints(points);
                        b->setTrack(gn->track());
                        gn->add(b);
                        }
                   else if (transition == 3) {
                         // TODO:
                         //     major: replace with a 'hammer-on' guitar effect when implemented
                         //     minor: make slurs for parts
 
                         ChordRest* cr1 = static_cast<Chord*>(gc);
                         ChordRest* cr2 = static_cast<Chord*>(note->chord());
 
                         Slur* slur = new Slur(score);
                         slur->setAnchor(Spanner::Anchor::CHORD);
                         slur->setStartElement(cr1);
                         slur->setEndElement(cr2);
                         slur->setTick(cr1->tick());
                         slur->setTick2(cr2->tick());
                         slur->setTrack(cr1->track());
                         slur->setTrack2(cr2->track());
                         // this case specifies only two-note slurs, don't set a parent
                         score->undoAddElement(slur);
                         }
                  }
            if (modMask2 & EFFECT_STACATTO) {   // staccato
                  Chord* chord = note->chord();
                  Articulation* a = new Articulation(chord->score());
                  a->setSymId(SymId::articStaccatoAbove);
                  chord->add(a);
                  }
            if (modMask2 & EFFECT_PALM_MUTE)
                  addPalmMute(note->chord(), note->staffIdx(), true);
            else
                  addPalmMute(note->chord(), note->staffIdx(), false);
 
            if (modMask2 & EFFECT_TREMOLO) {    // tremolo picking length
                  int tremoloDivision = readUChar();
                  Chord* chord = note->chord();
                  Tremolo* t = new Tremolo(chord->score());
                  if (tremoloDivision == 1) {
                        t->setTremoloType(TremoloType::R8);
                        chord->add(t);
                        }
                  else if (tremoloDivision == 2) {
                        t->setTremoloType(TremoloType::R16);
                        chord->add(t);
                        }
                  else if (tremoloDivision == 3) {
                        t->setTremoloType(TremoloType::R32);
                        chord->add(t);
                        }
                  else
                        qDebug("Unknown tremolo value");
                  }
            if (modMask2 & EFFECT_SLIDE) {
                  int slideKind = readUChar();
                  // if slide >= 4 then we are not dealing with legato slide nor shift slide
                  if (slideKind >= 3 || slideKind == 254 || slideKind == 255) {
                        slide = slideKind;
                        }
                  else
                        slides[note->chord()->track()] = slideKind;
                  }
            if (modMask2 & 0x10)
                  readUChar();      // harmonic kind
            if (modMask2 & EFFECT_TRILL) {
                  readUChar();      // trill fret
                  readUChar();      // trill length
 
                  // add the trill articulation to the note
                  Articulation* art = new Articulation(note->score());
                  art->setSymId(SymId::ornamentTrill);
                  if (!note->score()->addArticulation(note, art))
                        delete art;
 
                  }
            }
      else {
            addLetRing(note->chord(), note->staffIdx(), false);
            }
      if (fretNumber == -1) {
            qDebug("Note: no fret number, tie %d", tieNote);
            }
      Staff* staff = note->staff();
      if (fretNumber == 255) {
            fretNumber = 0;
            note->setHeadGroup(NoteHead::Group::HEAD_CROSS);
            note->setGhost(true);
            }
      // dead note represented as high numbers - fix to zero
      if (fretNumber > 99 || fretNumber == -1)
            fretNumber = 0;
      int pitch = staff->part()->instrument()->stringData()->getPitch(string, fretNumber, nullptr, 0);
      note->setFret(fretNumber);
      note->setString(string);
      note->setPitch(pitch);
 
      if (tieNote) {
            bool found = false;
            Chord* chord     = note->chord();
            Segment* segment = chord->segment()->prev1(SegmentType::ChordRest);
            int track        = note->track();
            while (segment) {
                  Element* e = segment->element(track);
                  if (e) {
                        if (e->type() == ElementType::CHORD) {
                              Chord* chord2 = static_cast<Chord*>(e);
                              foreach(Note* note2, chord2->notes()) {
                                    if (note2->string() == string) {
                                          Tie* tie = new Tie(score);
                                          tie->setEndNote(note);
                                          note2->add(tie);
                                          note->setFret(note2->fret());
                                          note->setPitch(note2->pitch());
                                          found = true;
                                          break;
                                          }
                                    }
                              }
                        if (found)
                              break;
                        }
                  segment = segment->prev1(SegmentType::ChordRest);
                  }
            if (!found)
                  qDebug("tied note not found, pitch %d fret %d string %d", note->pitch(), note->fret(), note->string());
            }
      return slur;
      }
 
//---------------------------------------------------------
//   readInfo
//---------------------------------------------------------
 
void GuitarPro4::readInfo()
      {
      title        = readDelphiString();
      subtitle     = readDelphiString();
      artist       = readDelphiString();
      album        = readDelphiString();
      composer     = readDelphiString();
      QString copyright = readDelphiString();
      if (!copyright.isEmpty())
            score->setMetaTag("copyright", QString("%1").arg(copyright));
 
      transcriber  = readDelphiString();
      instructions = readDelphiString();
      int n = readInt();
      for (int i = 0; i < n; ++i)
            comments.append(readDelphiString());
      }
 
//---------------------------------------------------------
//   convertGP4SlideNum
//---------------------------------------------------------
 
int GuitarPro4::convertGP4SlideNum(int slide)
      {
      switch (slide) {
            // slide out downwards
            case 3:
                  return SLIDE_OUT_DOWN;
                  break;
            // slide out upwards
            case 4:
                  return SLIDE_OUT_UP;
                  break;
            // slide in from above
            case 254:
                  return SLIDE_IN_ABOVE;
                  break;
            // slide in from below
            case 255:
                  return SLIDE_IN_BELOW;
                  break;
            }
      return slide;
      }
 
//---------------------------------------------------------
//   read
//---------------------------------------------------------
 
void GuitarPro4::read(QFile* fp)
      {
      f      = fp;
      curPos = 30;
 
      readInfo();
      readUChar();      // triplet feeling
      readLyrics();
 
      int tempo  = readInt();
      key        = readInt();
      /*int octave =*/ readUChar();    // octave
 
      //previousDynamic = new int [staves * VOICES];
      // initialise the dynamics to 0
      //for (int i = 0; i < staves * VOICES; i++)
      //      previousDynamic[i] = 0;
      previousDynamic = -1;
      previousTempo = -1;
 
      readChannels();
      measures = readInt();
      staves   = readInt();
 
      int tnumerator   = 4;
      int tdenominator = 4;
      for (int i = 0; i < measures; ++i) {
            GpBar bar;
            uchar barBits = readUChar();
            if (barBits & SCORE_TIMESIG_NUMERATOR)
                  tnumerator = readUChar();
            if (barBits & SCORE_TIMESIG_DENOMINATOR)
                  tdenominator = readUChar();
            if (barBits & SCORE_REPEAT_START)
                  bar.repeatFlags = bar.repeatFlags | Repeat::START;
            if (barBits & SCORE_REPEAT_END) {                // number of repeats
                  bar.repeatFlags = bar.repeatFlags | Repeat::END;
                  bar.repeats = readUChar() + 1;
                  }
            if (barBits & SCORE_VOLTA) {                      // a volta
                  uchar voltaNumber = readUChar();
                  while (voltaNumber > 0) {
                        // volta information is represented as a binary number
                        bar.volta.voltaType = GP_VOLTA_BINARY;
                        bar.volta.voltaInfo.append(voltaNumber & 1);
                        voltaNumber >>= 1;
                        }
                  }
            if (barBits & SCORE_MARKER) {
                  bar.marker = readDelphiString();     // new section?
                  /*int color = */ readInt();    // color?
                  }
            if (barBits & SCORE_KEYSIG) {
                  int currentKey = readUChar();
                  /* key signatures are specified as
                   * 1# = 1, 2# = 2, ..., 7# = 7
                   * 1b = 255, 2b = 254, ... 7b = 249 */
                  bar.keysig = currentKey <= 7 ? currentKey : -256+currentKey;
                  readUChar();        // specifies major/minor mode
                  }
            if (barBits & SCORE_DOUBLE_BAR)
                  bar.barLine = BarLineType::DOUBLE;
            bar.timesig = Fraction(tnumerator, tdenominator);
            bars.append(bar);
            }
 
      //
      // create a part for every staff
      //
      for (int staffIdx = 0; staffIdx < staves; ++staffIdx) {
            Part* part = new Part(score);
            Staff* s = new Staff(score);
            s->setPart(part);
            part->insertStaff(s, 0);
            score->staves().push_back(s);
            score->appendPart(part);
            }
 
      createMeasures();
 
      for (int i = 0; i < staves; ++i) {
            int tuning[GP_MAX_STRING_NUMBER];
 
            uchar c = readUChar();   // simulations bitmask
            if (c & 0x2) {                // 12 stringed guitar
                  }
            if (c & 0x4) {                // banjo track
                  }
            QString name = readPascalString(40);
            int strings  = readInt();
            if (strings <= 0 || strings > GP_MAX_STRING_NUMBER)
                  throw GuitarProError::GP_BAD_NUMBER_OF_STRINGS ;
            for (int j = 0; j < strings; ++j)
                  tuning[j] = readInt();
            for (int j = strings; j < GP_MAX_STRING_NUMBER; ++j)
                  readInt();
            int midiPort     = readInt() - 1;
            int midiChannel  = readInt() - 1;
            /*int midiChannel2 =*/ readInt(); // - 1;
            int frets        = readInt();
 
            int capo         = readInt();
            /*int color        =*/ readInt();
 
            int tuning2[strings];
            for (int k = 0; k < strings; ++k)
                  tuning2[strings-k-1] = tuning[k];
            StringData stringData(frets, strings, tuning2);
            Part* part = score->staff(i)->part();
            Instrument* instr = part->instrument();
            instr->setStringData(stringData);
            part->setPartName(name);
            part->setPlainLongName(name);
 
            //
            // determine clef
            //
            Staff* staff = score->staff(i);
            int patch = channelDefaults[midiChannel].patch;
            ClefType clefId = ClefType::G;
            if (midiChannel == GP_DEFAULT_PERCUSSION_CHANNEL) {
                  clefId = ClefType::PERC;
                  // instr->setUseDrumset(DrumsetKind::GUITAR_PRO);
                  instr->setDrumset(gpDrumset);
                  staff->setStaffType(0, StaffType::preset(StaffTypes::PERC_DEFAULT));
                  }
            else if (patch >= 24 && patch < 32)
                  clefId = ClefType::G8_VB;
            else if (patch >= 32 && patch < 40)
                  clefId = ClefType::F8_VB;
            Measure* measure = score->firstMeasure();
            Clef* clef = new Clef(score);
            clef->setClefType(clefId);
            clef->setTrack(i * VOICES);
            Segment* segment = measure->getSegment(SegmentType::HeaderClef, 0);
            segment->add(clef);
 
            if (capo > 0) {
                  Segment* s = measure->getSegment(SegmentType::ChordRest, measure->tick());
                  StaffText* st = new StaffText(score);
                  st->setPlainText(QString("Capo. fret ") + QString::number(capo));
                  st->setParent(s);
                  st->setTrack(i * VOICES);
                  measure->add(st);
            }
 
            Channel* ch = instr->channel(0);
            if (midiChannel == GP_DEFAULT_PERCUSSION_CHANNEL) {
                  ch->program = 0;
                  ch->bank    = 128;
                  }
            else {
                  ch->program = patch;
                  ch->bank    = 0;
                  }
            ch->volume  = channelDefaults[midiChannel].volume;
            ch->pan     = channelDefaults[midiChannel].pan;
            ch->chorus  = channelDefaults[midiChannel].chorus;
            ch->reverb  = channelDefaults[midiChannel].reverb;
            staff->part()->setMidiChannel(midiChannel, midiPort);
            // missing: phase, tremolo
            ch->updateInitList();
            }
 
      slurs = new Slur*[staves];
      letRings = new Pedal*[staves];
      palmMutes = new TextLine*[staves];
      for (int i = 0; i < staves; ++i) {
            slurs[i] = 0;
            letRings[i] = 0;
            palmMutes[i] = 0;
            }
 
      Measure* measure = score->firstMeasure();
      bool mixChange = false;
      for (int bar = 0; bar < measures; ++bar, measure = measure->nextMeasure()) {
            const GpBar& gpbar = bars[bar];
 
            if (!gpbar.marker.isEmpty()) {
                  Text* s = new RehearsalMark(score);
                  s->setPlainText(gpbar.marker.trimmed());
                  s->setTrack(0);
                  Segment* segment = measure->getSegment(SegmentType::ChordRest, measure->tick());
                  segment->add(s);
                  }
 
            Tuplet* tuplets[staves];
            for (int staffIdx = 0; staffIdx < staves; ++staffIdx)
                  tuplets[staffIdx] = 0;
 
            for (int staffIdx = 0; staffIdx < staves; ++staffIdx) {
                  Fraction measureLen = 0;
                  int tick  = measure->tick();
                  int beats = readInt();
                  int track = staffIdx * VOICES;
                  for (int beat = 0; beat < beats; ++beat) {
                        slide = -1;
                        if (slides.contains(track))
                              slide = slides.take(track);
 
                        uchar beatBits = readUChar();
                        bool dotted = beatBits & 0x1;
                        int pause = -1;
                        if (beatBits & BEAT_PAUSE)
                              pause = readUChar();
                        int len = readChar();
                        int tuple = 0;
                        if (beatBits & BEAT_TUPLET)
                              tuple = readInt();
                        Segment* segment = measure->getSegment(SegmentType::ChordRest, tick);
                        if (beatBits & BEAT_CHORD) {
                              int numStrings = score->staff(staffIdx)->part()->instrument()->stringData()->strings();
                              int header = readUChar();
                              QString name;
                              if ((header & 1) == 0) {
                                    name = readDelphiString();
                                    readChord(segment, staffIdx * VOICES, numStrings, name, false);
                                    }
                              else  {
                                    skip(16);
                                    name = readPascalString(21);
                                    skip(4);
                                    readChord(segment, staffIdx * VOICES, numStrings, name, true);
                                    skip(32);
                                    }
                              }
                        Lyrics* lyrics = 0;
                        if (beatBits & BEAT_LYRICS) {
                              lyrics = new Lyrics(score);
                              lyrics->setPlainText(readDelphiString());
                              }
                        gpLyrics.beatCounter++;
                        if (gpLyrics.beatCounter >= gpLyrics.fromBeat && gpLyrics.lyricTrack == staffIdx + 1) {
                              int index = gpLyrics.beatCounter - gpLyrics.fromBeat;
                              if (index < gpLyrics.lyrics.size()) {
                                    lyrics = new Lyrics(score);
                                    lyrics->setPlainText(gpLyrics.lyrics[index]);
                                    }
                              }
                        int beatEffects = 0;
                        if (beatBits & BEAT_EFFECTS)
                              beatEffects = readBeatEffects(track, segment);
                        if (beatBits & BEAT_MIX_CHANGE) {
                              readMixChange(measure);
                              mixChange = true;
                              }
                        else  {
                              if (bar == 0)
                                    setTempo(tempo, measure);
                              }
 
 
                        int strings = readUChar();   // used strings mask
                        Fraction l  = len2fraction(len);
 
                        // Some beat effects could add a Chord before this
                        ChordRest* cr = segment->cr(track);
 
                        if (strings == 0) {
                              if(segment->cr(track)){
                                    segment->remove(segment->cr(track));
                                    delete cr;
                                    cr = 0;
                                    }
                              cr = new Rest(score);
                              }
                        else {
                              if(!segment->cr(track))
                                    cr = new Chord(score);
                              }
 
                        cr->setTrack(track);
                        if (lyrics)
                              cr->add(lyrics);
 
                        TDuration d(l);
                        d.setDots(dotted ? 1 : 0);
 
                        if (dotted)
                              l = l + (l/2);
 
                        if (tuple) {
                              Tuplet* tuplet = tuplets[staffIdx];
                              if ((tuplet == 0) || (tuplet->elementsDuration() == tuplet->baseLen().fraction() * tuplet->ratio().numerator())) {
                                    tuplet = new Tuplet(score);
                                    tuplet->setTrack(cr->track());
                                    tuplets[staffIdx] = tuplet;
                                    setTuplet(tuplet, tuple);
                                    tuplet->setParent(measure);
                                    }
                              tuplet->setTrack(track);
                              tuplet->setBaseLen(l);
                              tuplet->setDuration(l * tuplet->ratio().denominator());
                              cr->setTuplet(tuplet);
                              tuplet->add(cr);
                              }
 
                        cr->setDuration(l);
                        if (cr->type() == ElementType::REST && (pause == 0 || l >= measure->len())) {
                              cr->setDurationType(TDuration::DurationType::V_MEASURE);
                              cr->setDuration(measure->len());
                              }
                        else
                              cr->setDurationType(d);
                        if(!segment->cr(track))
                              segment->add(cr);
                        Staff* staff = cr->staff();
                        int numStrings = staff->part()->instrument()->stringData()->strings();
                        bool hasSlur = false;
                        for (int i = 6; i >= 0; --i) {
                              if (strings & (1 << i) && ((6-i) < numStrings)) {
                                    Note* note = new Note(score);
                                    // apply dotted notes to the note
                                    if (dotted) {
                                          // there is at most one dotted note in this guitar pro version
                                          NoteDot* dot = new NoteDot(score);
                                          // dot->setIdx(0);
                                          dot->setParent(note);
                                          dot->setTrack(track);  // needed to know the staff it belongs to (and detect tablature)
                                          dot->setVisible(true);
                                          note->add(dot);
                                          }
                                    static_cast<Chord*>(cr)->add(note);
 
                                    hasSlur = readNote(6-i, staffIdx, note);
                                    note->setTpcFromPitch();
                                    }
                              }
                        if (cr && (cr->type() == ElementType::CHORD))
                              applyBeatEffects(static_cast<Chord*>(cr), beatEffects);
 
                        // if we see that a tied note has been constructed do not create the tie
                        if (slides[track] == -2) {
                              slide = 0;
                              slides[track] = -1;
                              }
                        createSlur(hasSlur, staffIdx, cr);
                        if (cr && (cr->type() == ElementType::CHORD) && slide > 0)
                              createSlide(convertGP4SlideNum(slide), cr, staffIdx);
                        restsForEmptyBeats(segment, measure, cr, l, track, tick);
                        createSlur(hasSlur, staffIdx, cr);
                        tick += cr->actualTicks();
                        measureLen += cr->actualFraction();
                        }
                  if (measureLen < measure->len()) {
                        score->setRest(tick, track, measure->len() - measureLen, false, nullptr, false);
                        }
                  }
            if (bar == 1 && !mixChange)
                  setTempo(tempo, score->firstMeasure());
            }
      }
 
}

V688 The 'f' local variable possesses the same name as one of the class members, which can result in a confusion.

V581 The conditional expressions of the 'if' statements situated alongside each other are identical. Check lines: 285, 289.

V560 A part of conditional expression is always false: slideKind == 254.

V560 A part of conditional expression is always false: slideKind == 255.

V688 The 'tempo' local variable possesses the same name as one of the class members, which can result in a confusion.

V773 The 'lyrics' pointer was assigned values twice without releasing the memory. A memory leak is possible.

V595 The 'cr' pointer was utilized before it was verified against nullptr. Check lines: 811, 836.