LCOV - code coverage report
Current view: top level - src/importexport/guitarpro/internal - importptb.cpp Coverage Total Hit
Test: filtered_coverage.info Lines: 45.8 % 872 399
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              : #include "importptb.h"
      23              : #include "assert.h"
      24              : 
      25              : #include <cmath>
      26              : 
      27              : #include "engraving/dom/articulation.h"
      28              : #include "engraving/dom/bend.h"
      29              : #include "engraving/dom/box.h"
      30              : #include "engraving/dom/chord.h"
      31              : #include "engraving/dom/clef.h"
      32              : #include "engraving/dom/factory.h"
      33              : #include "engraving/dom/instrument.h"
      34              : #include "engraving/dom/masterscore.h"
      35              : #include "engraving/dom/measure.h"
      36              : #include "engraving/dom/note.h"
      37              : #include "engraving/dom/palmmute.h"
      38              : #include "engraving/dom/part.h"
      39              : #include "engraving/dom/rehearsalmark.h"
      40              : #include "engraving/dom/rest.h"
      41              : #include "engraving/dom/staff.h"
      42              : #include "engraving/dom/tempotext.h"
      43              : #include "engraving/dom/text.h"
      44              : #include "engraving/dom/tie.h"
      45              : #include "engraving/dom/timesig.h"
      46              : #include "engraving/dom/tuplet.h"
      47              : 
      48              : #include "engraving/types/symid.h"
      49              : 
      50              : #include "log.h"
      51              : 
      52              : using namespace mu::engraving;
      53              : 
      54              : namespace mu::iex::guitarpro {
      55            0 : bool PowerTab::readBoolean()
      56              : {
      57            0 :     return readUInt8() != 0;
      58              : }
      59              : 
      60          187 : uint8_t PowerTab::readUInt8()
      61              : {
      62              :     uint8_t byte;
      63          187 :     _file->read((uint8_t*)&byte, 1);
      64          187 :     return byte;
      65              : }
      66              : 
      67          134 : unsigned short PowerTab::readShort()
      68              : {
      69              :     uint16_t val;
      70          134 :     _file->read((uint8_t*)&val, 2);
      71          134 :     return val;
      72              : }
      73              : 
      74           81 : char PowerTab::readChar()
      75              : {
      76              :     char byte;
      77           81 :     _file->read((uint8_t*)&byte, 1);
      78           81 :     return byte;
      79              : }
      80              : 
      81           24 : int PowerTab::readInt()
      82              : {
      83              :     int32_t val;
      84           24 :     _file->read((uint8_t*)&val, 4);
      85           24 :     return val;
      86              : }
      87              : 
      88           19 : std::string PowerTab::readString(int length)
      89              : {
      90           19 :     if (length == 0) {
      91            0 :         LOGE() << "reading string of length zero";
      92            0 :         return std::string();
      93              :     }
      94              : 
      95           19 :     if (length == -1) {
      96           16 :         length = readUInt8();
      97           16 :         if (length == 0xFF) {
      98            0 :             length = readShort();
      99              :         }
     100              :     }
     101           19 :     char* p = new char[length];
     102           19 :     _file->read((uint8_t*)p, length);
     103              : 
     104           19 :     std::string s(p, length);
     105           19 :     delete[] p;
     106           19 :     return s;
     107           19 : }
     108              : 
     109            3 : bool PowerTab::readVersion()
     110              : {
     111            3 :     std::string version = readString(4);
     112            9 :     version += std::string("-") + std::to_string(readShort());
     113            6 :     return version == "ptab-4";
     114            3 : }
     115              : 
     116           18 : void PowerTab::skip(int len /* = 1 */)
     117              : {
     118           90 :     for (int i = 0; i < len; ++i) {
     119           72 :         readChar();
     120              :     }
     121           18 : }
     122              : 
     123            3 : void PowerTab::readSongInfo(ptSongInfo& info)
     124              : {
     125            3 :     auto classification = readChar();
     126            3 :     info.classification = classification;
     127            3 :     if (classification == 0) {
     128            0 :         skip(1);
     129            0 :         info.name = readString();
     130            0 :         info.interpret = readString();
     131              : 
     132            0 :         auto releaseType = readChar();
     133              : 
     134            0 :         switch (releaseType) {
     135            0 :         case 0: {
     136              :             /*auto albumType =*/
     137            0 :             readChar();
     138            0 :             info.album = readString();
     139            0 :             info.year = readShort();
     140            0 :             info.liverecording = readChar() != 0;
     141            0 :             break;
     142              :         }
     143            0 :         case 1: {
     144            0 :             info.album = readString();
     145            0 :             info.liverecording = readChar() != 0;
     146            0 :             break;
     147              :         }
     148            0 :         case 2: {
     149            0 :             info.album  = readString();
     150            0 :             info.day    = readShort();
     151            0 :             info.month  = readShort();
     152            0 :             info.year   = readShort();
     153            0 :             break;
     154              :         }
     155            0 :         case 3: {
     156            0 :             break;
     157              :         }
     158            0 :         default:
     159            0 :             assert(0);
     160              :         }
     161              : 
     162            0 :         if (readChar() == 0) {
     163            0 :             info.author = readString();
     164            0 :             info.lyricist = readString();
     165              :         }
     166              : 
     167            0 :         info.arranger           = readString();
     168            0 :         info.guitarTranscriber  = readString();
     169            0 :         info.bassTranscriber    = readString();
     170            0 :         info.copyright          = readString();
     171              : 
     172            0 :         info.lyrics             = readString();
     173              : 
     174            0 :         info.guitarInstructions = readString();
     175            0 :         info.bassInstructions   = readString();
     176            3 :     } else if (classification == 1) {
     177            0 :         info.name         = readString();
     178            0 :         info.album        = readString();
     179            0 :         info.style        = readShort();
     180            0 :         info.level        = readUInt8();
     181            0 :         info.author       = readString();
     182            0 :         info.instructions = readString();
     183            0 :         info.copyright    = readString();
     184              :     }
     185            3 : }
     186              : 
     187           96 : int PowerTab::readHeaderItems()
     188              : {
     189           96 :     int itemCount = readShort();
     190           96 :     if (itemCount != 0) {
     191           29 :         int header = readShort();
     192           29 :         if (header == 0xFFFF) {
     193            0 :             if (readShort() != 1) {
     194            0 :                 return -1;
     195              :             }
     196            0 :             auto str = readString(readShort());       //section title
     197            0 :         }
     198              :     }
     199           96 :     return itemCount;
     200              : }
     201              : 
     202            5 : void PowerTab::readTrackInfo(ptTrack& info)
     203              : {
     204            5 :     TrackInfo tr;
     205              : 
     206            5 :     tr.number = readUInt8();
     207            5 :     tr.name = readString();
     208            5 :     tr.instrument = readUInt8();
     209            5 :     tr.volume = readUInt8();
     210            5 :     tr.balance = readUInt8();
     211            5 :     tr.reverb = readUInt8();
     212            5 :     tr.chorus = readUInt8();
     213            5 :     tr.tremolo = readUInt8();
     214            5 :     tr.phaser = readUInt8();
     215            5 :     tr.capo = readUInt8();
     216            5 :     tr.tuningName = readString();
     217            5 :     tr.offset = readUInt8();
     218              : 
     219            5 :     int ln = readUInt8();
     220           25 :     for (int i = 0; i < ln; ++i) {
     221           20 :         tr.strings.push_back(readUInt8());
     222              :     }
     223            5 :     info.infos.push_back(tr);
     224            5 : }
     225              : 
     226            0 : void PowerTab::readChord(ptTrack& info)
     227              : {
     228            0 :     ptChord ch;
     229            0 :     ch.key = readShort();   //chord key
     230            0 :     ch.formula = readUInt8();
     231            0 :     ch.modification = readShort();   //Chord Modification
     232            0 :     ch.extra = readUInt8();
     233            0 :     ch.top_fret = readUInt8();
     234            0 :     auto stringCount = readUInt8();
     235            0 :     for (int i = 0; i < stringCount; ++i) {
     236            0 :         ch.frets.push_back(readUInt8());     // fret
     237              :     }
     238            0 :     if (info.diagramMap.find({ { ch.key, ch.formula, ch.modification } }) == info.diagramMap.end()) {
     239            0 :         info.diagramMap[ { { ch.key, ch.formula, ch.modification } }] = ch;
     240              :     } else {
     241            0 :         auto a1 = info.diagramMap[ { { ch.key, ch.formula, ch.modification } }];
     242            0 :         auto a2 = ch;
     243              : 
     244              : //??            int k = 1;
     245            0 :     }
     246            0 : }
     247              : 
     248            0 : void PowerTab::readFontSettings()
     249              : {
     250            0 :     readString();   //font name
     251            0 :     readInt();   // point size
     252            0 :     readInt();   // weight
     253            0 :     readBoolean();   //italic
     254            0 :     readBoolean();   //underline
     255            0 :     readBoolean();   //strikeout
     256            0 :     readInt();   //color
     257            0 : }
     258              : 
     259            0 : void PowerTab::readFloatingText()
     260              : {
     261            0 :     readString();   //text
     262              :     //rect :
     263            0 :     readInt();   // left
     264            0 :     readInt();   // top
     265            0 :     readInt();   // right
     266            0 :     readInt();   // bottom
     267              : 
     268            0 :     readUInt8();
     269            0 :     readFontSettings();
     270            0 : }
     271              : 
     272            0 : void PowerTab::readDynamic()
     273              : {
     274            0 :     readShort();
     275            0 :     readUInt8();
     276            0 :     readUInt8();
     277            0 :     readShort();
     278            0 : }
     279              : 
     280            6 : void PowerTab::readKeySignature()
     281              : {
     282            6 :     readUInt8();
     283            6 : }
     284              : 
     285            6 : void PowerTab::readRehearsalSign(ptSection& sec)
     286              : {
     287            6 :     auto c = readChar();
     288            6 :     auto str = readString();
     289            6 :     if (str.size()) {
     290            0 :         sec.partName = str;
     291            0 :         sec.partMarker = c;
     292              :     }
     293            6 : }
     294              : 
     295            0 : void PowerTab::readChordText(ptSection& sec)
     296              : {
     297            0 :     ptChordText cht;
     298            0 :     cht.position = readUInt8();
     299            0 :     cht.key = readShort();
     300            0 :     cht.formula = readUInt8();
     301            0 :     cht.formula_mod = readShort();
     302            0 :     cht.extra = readUInt8();
     303              :     //sec.chordTextMap.push_back(cht);
     304            0 :     sec.chordTextMap.insert({ cht.position, cht });
     305            0 : }
     306              : 
     307            0 : void PowerTab::readRhytmSlash(ptSection& sec)
     308              : {
     309            0 :     stRhytmSlash rs;
     310            0 :     rs.position = readUInt8();
     311            0 :     auto beaming = readUInt8();
     312            0 :     auto data = readInt();
     313            0 :     auto duration = (data & 0xE00000) >> 21;
     314            0 :     switch (duration) {
     315            0 :     case 0:
     316            0 :         rs.duration = 1;
     317            0 :         break;
     318            0 :     case 1:
     319            0 :         rs.duration = 2;
     320            0 :         break;
     321            0 :     case 2:
     322            0 :         rs.duration = 4;
     323            0 :         break;
     324            0 :     case 3:
     325            0 :         rs.duration = 8;
     326            0 :         break;
     327            0 :     case 4:
     328            0 :         rs.duration = 16;
     329              :     }
     330              : 
     331            0 :     rs.triplet = beaming & (0x20 | 0x40);
     332            0 :     rs.tripletend = beaming & 0x80;
     333              : 
     334            0 :     rs.dotted = data & 0x01;
     335            0 :     rs.doubleDotted = data & 0x02;
     336              : 
     337            0 :     rs.is_rest = data & 0x04;
     338              : 
     339            0 :     sec.rhythm.emplace_back(rs);
     340            0 : }
     341              : 
     342            0 : void PowerTab::readGuitarIn(ptTrack& info)
     343              : {
     344            0 :     ptGuitarIn gin;
     345            0 :     gin.section = readShort();
     346            0 :     gin.staff = readUInt8() + staffInc;
     347            0 :     gin.position = readUInt8();
     348            0 :     gin.rhythmSlash = readUInt8();
     349            0 :     gin.trackinfo = readUInt8();
     350            0 :     info.guitar_ins.push_back(gin);
     351            0 : }
     352              : 
     353            0 : void PowerTab::readTempoMarker(ptTrack& info)
     354              : {
     355            0 :     auto section = readShort();
     356            0 :     /*auto position =*/ readUInt8();
     357            0 :     auto tempo = readShort();
     358            0 :     /*auto data =*/ readShort();
     359            0 :     readString();   //description
     360              : 
     361            0 :     if (tempo > 0) {
     362            0 :         info.getSection(section).tempo = tempo;
     363              :     }
     364            0 : }
     365              : 
     366            0 : void PowerTab::readSectionSymbol(ptTrack& info)
     367              : {
     368            0 :     int section = readShort();
     369            0 :     int position = readUInt8();
     370            0 :     int data = readInt();
     371              : 
     372            0 :     int endNumber = data >> 16;
     373            0 :     info.getSection(section).getPosition(position).addComponent(new ptSymbol(endNumber));
     374            0 : }
     375              : 
     376            6 : void PowerTab::readTimeSignature(ptBar* bar)
     377              : {
     378            6 :     skip(3);
     379            6 :     int data = readUInt8();
     380            6 :     readUInt8();   // measure pulses
     381              : 
     382            6 :     bar->numerator = ((data - (data % 8)) / 8) + 1;
     383            6 :     bar->denominator = pow(2, data % 8);
     384            6 : }
     385              : 
     386            6 : void PowerTab::readBarLine(ptSection& sec)
     387              : {
     388            6 :     auto bar = new ptBar();
     389            6 :     /*int position =*/ readUInt8();
     390            6 :     auto b_type = readUInt8();
     391              : 
     392            6 :     bar->repeatStart = (b_type >> 5) == 3;
     393            6 :     bar->repeatClose = (b_type >> 5) == 4 ? b_type - 128 : 0;
     394              : 
     395            6 :     bar->measureNo = sec.number;
     396              : 
     397            6 :     readKeySignature();
     398            6 :     readTimeSignature(bar);
     399            6 :     readRehearsalSign(sec);
     400              :     //sec.getPosition(position).addComponent(bar);
     401            6 :     sec.bars.push_back(std::shared_ptr<ptBar>(bar));
     402              :     /*if (bars.empty() || ( bars.back()->measureNo < bar->measureNo ))
     403              :           bars.push_back(bar);*/
     404            6 : }
     405              : 
     406            6 : void PowerTab::readStaff(int staff, ptSection& sec)
     407              : {
     408            6 :     skip(5);
     409           18 :     for (int voice = 0; voice < 2; ++voice) {
     410           12 :         int itemCount = readHeaderItems();
     411           18 :         for (int i = 0; i < itemCount; ++i) {
     412            6 :             readPosition(staff, voice, sec);
     413            6 :             if (i < itemCount - 1) {
     414            0 :                 readShort();
     415              :             }
     416              :         }
     417              :     }
     418            6 : }
     419              : 
     420            6 : void PowerTab::readNote(ptBeat* beat)
     421              : {
     422            6 :     ptNote note;
     423            6 :     auto position = readUInt8();
     424            6 :     auto simpleData = readShort();
     425            6 :     auto symbolCount = readUInt8();
     426            6 :     for (int i = 0; i < symbolCount; ++i) {
     427            0 :         skip(2);
     428            0 :         auto data3 = readUInt8();
     429            0 :         auto data4 = readUInt8();
     430            0 :         note.bend = data4 == 101 ? data3 / 16 + 1 : 0;
     431            0 :         note.slide = data4 == 100 ? data3 + 1 : 0;
     432              :     }
     433            6 :     note.value = position & 0x1F;
     434            6 :     note.str = ((position & 0xE0) >> 5);
     435            6 :     note.tied = simpleData & 0x01;
     436            6 :     note.dead = simpleData & 0x02;
     437            6 :     note.hammer = simpleData & 0x08;
     438            6 :     beat->notes.emplace_back(note);
     439            6 : }
     440              : 
     441            6 : void PowerTab::readPosition(int staff, int voice, ptSection& sec)
     442              : {
     443            6 :     auto position = readUInt8();
     444              : 
     445            6 :     ptBeat beat = ptBeat();
     446            6 :     beat.position = position;
     447            6 :     beat.voice = voice;
     448            6 :     bool add = false;
     449            6 :     if (voice == 0 || static_cast<size_t>(staff) >= sec.beats.size() || sec.beats[staff].empty()) {
     450            6 :         beat = ptBeat(staff, voice);
     451            6 :         beat.position = position;
     452            6 :         add = true;
     453              :     }
     454            6 :     auto beaming = readUInt8();
     455            6 :     beaming = (((int)beaming - 128 < 0) ? beaming : beaming - 128);
     456              : 
     457            6 :     readUInt8();
     458              : 
     459            6 :     auto data1 = readUInt8();
     460            6 :     auto data2 = readUInt8();   //32 - palm mute, 4 - accent, 2 - staccato
     461            6 :     auto data3 = readUInt8();
     462            6 :     auto durationValue = readUInt8();
     463              : 
     464            6 :     int multiBarRest = 1;
     465            6 :     auto complexCount = readUInt8();
     466            6 :     for (int i = 0; i < complexCount; ++i) {
     467            0 :         auto count = readShort();
     468            0 :         readUInt8();
     469            0 :         auto type = readUInt8();
     470            0 :         if (type & 0x08) {
     471            0 :             multiBarRest = count;
     472              :         }
     473              :     }
     474              : 
     475            6 :     auto itemCount = readHeaderItems();
     476           12 :     for (int i = 0; i < itemCount; ++i) {
     477            6 :         readNote(&beat);
     478            6 :         if (i < itemCount - 1) {
     479            0 :             readShort();
     480              :         }
     481              :     }
     482              : 
     483            6 :     if (staff < 0 || staff >= static_cast<int>(curTrack->infos.size())) {
     484            1 :         LOGE() << "Invalid staff index";
     485            1 :         return;
     486              :     }
     487            5 :     curTrack->infos[staff].notes_count += itemCount;
     488              : 
     489            5 :     beat.mmrest = (itemCount == 0) ? multiBarRest : 1;
     490            5 :     beat.vibrato = (((data1 & 0x08) != 0) || ((data1 & 0x10) != 0));
     491            5 :     beat.grace = (data3 & 0x01) != 0;
     492            5 :     beat.tuplet = (data3 & 0x20) != 0;
     493              : 
     494            5 :     if (beat.duration != 0) {
     495            0 :         durationValue = std::max((int)durationValue, beat.duration);
     496              :     }
     497              : 
     498            5 :     beat.duration = durationValue;
     499            5 :     beat.dotted = (data1 & 0x01);
     500            5 :     beat.doubleDotted = (data1 & 0x02);
     501            5 :     beat.arpeggioUp = (data1 & 0x20);
     502            5 :     beat.arpeggioDown = (data1 & 0x40);
     503            5 :     beat.enters = ((beaming - (beaming % 8)) / 8) + 1;
     504            5 :     beat.times = (beaming % 8) + 1;
     505            5 :     beat.isRest = (data1 & 0x04);
     506            5 :     beat.palmMute = data2 & 0x20;
     507            5 :     beat.accent = data2 & 0x04;
     508            5 :     beat.staccato = data2 & 0x02;
     509              : 
     510           10 :     for (int i = int(sec.beats.size()); i < staff + 1; ++i) {
     511            5 :         sec.beats.push_back({});
     512              :     }
     513            5 :     if (add) {
     514            5 :         sec.beats[staff].push_back(beat);
     515              :     }
     516              :     //sec.getPosition(position).addComponent(beat);
     517            6 : }
     518              : 
     519            6 : std::vector<int> PowerTab::getStaffMap(ptSection& sec)
     520              : {
     521            6 :     std::vector<int> result;
     522            6 :     std::vector<int> slash;
     523            6 :     if (!staffInc && curTrack->guitar_ins.size()) {
     524            0 :         auto first = curTrack->guitar_ins.front();
     525            0 :         while (first.section == sec.number) {
     526            0 :             if (first.trackinfo) {
     527            0 :                 for (unsigned int i = 0; i < curTrack->infos.size(); ++i) {
     528            0 :                     if ((1 << i) & first.trackinfo) {
     529            0 :                         result.push_back(i);
     530              :                     }
     531              :                 }
     532              :             }
     533              : 
     534            0 :             if (first.rhythmSlash) {
     535            0 :                 for (unsigned int i = 0; i < curTrack->infos.size(); ++i) {
     536            0 :                     if ((i << 1) & first.rhythmSlash) {
     537            0 :                         slash.push_back(-1 - i);
     538              :                     }
     539              :                 }
     540              :             }
     541              : 
     542            0 :             curTrack->guitar_ins.pop_front();
     543            0 :             if (curTrack->guitar_ins.empty()) {
     544            0 :                 break;
     545              :             }
     546            0 :             first = curTrack->guitar_ins.front();
     547              :         }
     548            0 :     }
     549              : 
     550            6 :     if (result.empty() || int(result.size()) < sec.staves) {
     551            6 :         result.clear();
     552            6 :         if (int(lastStaffMap.size()) < sec.staves) {
     553           12 :             for (int i = 0; i < sec.staves; ++i) {
     554            6 :                 result.push_back(i + staffInc);
     555              :             }
     556              :         } else {
     557            0 :             result = lastStaffMap;
     558              :         }
     559              :     }
     560              : 
     561              :     // negative numbers
     562              : //    for (auto i : slash) {
     563              : //        result.push_back(i);
     564              : //    }
     565              : 
     566            6 :     lastStaffMap = result;
     567            6 :     return result;
     568            6 : }
     569              : 
     570              : //---------------------------------------------------------
     571              : //   addPalmMate
     572              : //---------------------------------------------------------
     573              : 
     574            0 : void PowerTab::addPalmMute(Chord* chord)
     575              : {
     576            0 :     track_idx_t track = chord->track();
     577            0 :     while (_palmMutes.size() < track + 1) {
     578            0 :         _palmMutes.push_back(0);
     579              :     }
     580              : 
     581            0 :     if (_palmMutes[track]) {
     582            0 :         PalmMute* pm = _palmMutes[track];
     583            0 :         Chord* lastChord = toChord(pm->endCR());
     584            0 :         if (lastChord == chord) {
     585            0 :             return;
     586              :         }
     587              :         //
     588              :         // extend the current palm mute or start a new one
     589              :         //
     590            0 :         Fraction tick = chord->segment()->tick();
     591            0 :         if (pm->tick2() < tick) {
     592            0 :             _palmMutes[track] = 0;
     593              :         } else {
     594            0 :             pm->setTick2(chord->endTick());
     595            0 :             pm->setEndElement(chord);
     596              :         }
     597              :     }
     598            0 :     if (!_palmMutes[track]) {
     599            0 :         PalmMute* pm = new PalmMute(score->dummy());
     600            0 :         _palmMutes[track] = pm;
     601            0 :         Segment* segment = chord->segment();
     602            0 :         Fraction tick = segment->tick();
     603              : 
     604            0 :         pm->setTick(tick);
     605            0 :         pm->setTick2(tick + chord->actualTicks());
     606            0 :         pm->setTrack(track);
     607            0 :         pm->setTrack2(track);
     608            0 :         pm->setStartElement(chord);
     609            0 :         pm->setEndElement(chord);
     610            0 :         score->addElement(pm);
     611              :     }
     612              : }
     613              : 
     614            5 : void PowerTab::fillMeasure(tBeatList& elist, Measure* measure, int staff, std::vector<Note*>& tiedNotes)
     615              : {
     616            5 :     Tuplet* tuple = nullptr;
     617            5 :     int tupleBeatCounter{ 0 };
     618            5 :     Fraction tick = measure->tick();
     619            5 :     Fraction endtick = measure->endTick();
     620            5 :     Chord* hammer{ nullptr };
     621              : 
     622           10 :     while (elist.size() && tick < endtick) {
     623            5 :         auto& beat = elist.front();
     624            5 :         auto segment = measure->getSegment(SegmentType::ChordRest, tick);
     625            5 :         Fraction l(1, beat.duration);
     626            5 :         int dots = beat.dotted ? (beat.doubleDotted ? 2 : 1) : (beat.doubleDotted ? 2 : 0);
     627            5 :         switch (dots) {
     628            0 :         case 1:
     629            0 :             l = l + (l * Fraction(1, 2));
     630            0 :             break;
     631            0 :         case 2:
     632            0 :             l = l + (l * Fraction(3, 4));
     633            0 :             break;
     634              :         }
     635              : 
     636            5 :         TDuration d(l);
     637            5 :         d.setDots(dots);
     638              : 
     639            5 :         if (beat.tuplet || tupleBeatCounter) {
     640            0 :             Fraction nt = (l * Fraction(1, 3) * Fraction(2, 1));
     641            0 :             tick += nt;
     642            0 :         } else {
     643            5 :             tick += l;
     644              :         }
     645              :         ChordRest* cr;
     646            5 :         if (beat.notes.empty()) {
     647            0 :             auto rest = Factory::createRest(segment);
     648            0 :             cr = rest;
     649            0 :             rest->setTrack(staff * VOICES);
     650            0 :             rest->setTicks(l);
     651            0 :             rest->setDurationType(d);
     652            0 :             segment->add(rest);
     653              :         } else {
     654            5 :             Chord* chord = Factory::createChord(segment);
     655            5 :             cr = chord;
     656            5 :             chord->setTrack(staff * VOICES);
     657            5 :             chord->setTicks(l);
     658            5 :             chord->setDurationType(d);
     659            5 :             segment->add(chord);
     660              : 
     661            5 :             if (beat.palmMute) {
     662            0 :                 addPalmMute(chord);
     663              :             }
     664            5 :             if (beat.accent) {
     665            0 :                 auto accent = Factory::createArticulation(chord);
     666            0 :                 accent->setSymId(SymId::articAccentAbove);
     667            0 :                 chord->add(accent);
     668              :             }
     669            5 :             if (beat.staccato) {
     670            0 :                 auto st = Factory::createArticulation(chord);
     671            0 :                 st->setSymId(SymId::articStaccatoAbove);
     672            0 :                 chord->add(st);
     673              :             }
     674            5 :             bool has_hammer = false;
     675           10 :             for (const auto& n : beat.notes) {
     676            5 :                 if (n.str < 0 || static_cast<size_t>(n.str) >= tiedNotes.size()) {
     677            0 :                     LOGE() << "string index out of range, skipping note";
     678            0 :                     continue;
     679              :                 }
     680              : 
     681            5 :                 const std::vector<int>& trackStrings = curTrack->infos[staff].strings;
     682            5 :                 if (trackStrings.empty()) {
     683            1 :                     LOGE() << "track has no strings, skipping note";
     684            1 :                     continue;
     685              :                 }
     686              : 
     687            4 :                 const StringData* sd = score->staff(staff)->part()->instrument()->stringData();
     688            4 :                 const int k = std::max(int(trackStrings.size()) - n.str - 1, 0);
     689            4 :                 if (!sd || static_cast<size_t>(k) >= sd->stringList().size()) {
     690            0 :                     LOGE() << "string data missing for note pitch";
     691            0 :                     continue;
     692              :                 }
     693              : 
     694            4 :                 auto note = Factory::createNote(chord);
     695            4 :                 chord->add(note);
     696            4 :                 if (n.dead) {
     697            0 :                     note->setHeadGroup(NoteHeadGroup::HEAD_CROSS);
     698            0 :                     note->setGhost(true);
     699              :                 }
     700              : 
     701            4 :                 if (n.hammer) {
     702            0 :                     has_hammer = true;
     703              :                 }
     704              : 
     705            4 :                 if (n.tied && tiedNotes[n.str]) {
     706            0 :                     Tie* tie = Factory::createTie(tiedNotes[n.str]);
     707            0 :                     tie->setEndNote(note);
     708            0 :                     tiedNotes[n.str]->add(tie);
     709              :                 }
     710              : 
     711            4 :                 if (n.bend) {
     712            0 :                     Bend* bend = Factory::createBend(note);
     713              : //TODO-ws                              bend->setNote(note);
     714            0 :                     bend->points().push_back(PitchValue(0, n.bend * 25 - 12));
     715            0 :                     bend->points().push_back(PitchValue(50, 0));
     716            0 :                     note->add(bend);
     717              :                 }
     718              : 
     719              :                 if (false && n.slide) {
     720              :                     Text* st = Factory::createText(chord->notes().front(), TextStyleType::HARMONY_A);
     721              :                     st->setXmlText(String(u"SLIDE %1").arg(n.slide));
     722              :                     st->setTrack(staff * VOICES);
     723              :                     chord->notes().front()->add(st);
     724              :                 }
     725              : 
     726            4 :                 tiedNotes[n.str] = note;
     727            4 :                 note->setFret(n.value);
     728            4 :                 note->setString(n.str);
     729            4 :                 int pitch = sd->stringList().at(k).pitch + n.value;         //getPitch(n.str, n.value, 0);
     730            4 :                 note->setPitch(pitch);
     731            4 :                 note->setTpcFromPitch();
     732              :             }
     733              : 
     734            5 :             if (hammer) {
     735            0 :                 auto cr1 = hammer;
     736            0 :                 auto cr2 = chord;
     737            0 :                 hammer = nullptr;
     738              : 
     739            0 :                 Slur* slur = Factory::createSlur(score->dummy());
     740            0 :                 slur->setStartElement(cr1);
     741            0 :                 slur->setEndElement(cr2);
     742            0 :                 slur->setTick(cr1->tick());
     743            0 :                 slur->setTick2(tick);
     744            0 :                 slur->setTrack(staff * VOICES);
     745            0 :                 slur->setTrack2(staff * VOICES);
     746            0 :                 score->addElement(slur);
     747              : 
     748            0 :                 Text* st = Factory::createText(chord->notes().front(), TextStyleType::HARMONY_A);
     749            0 :                 st->setXmlText(u"H");
     750            0 :                 st->setTrack(staff * VOICES);
     751            0 :                 cr1->notes().front()->add(st);
     752              :             }
     753            5 :             if (has_hammer) {
     754            0 :                 hammer = chord;
     755              :             }
     756              :         }
     757              : 
     758            5 :         if (tupleBeatCounter && tuple) {
     759            0 :             tupleBeatCounter--;
     760            0 :             cr->setTuplet(tuple);
     761            0 :             tuple->add(cr);
     762              :         }
     763              : 
     764            5 :         if (beat.tuplet && !tuple) {
     765            0 :             tuple = Factory::createTuplet(measure);
     766            0 :             tuple->setTrack(cr->track());
     767            0 :             tuple->setTick(cr->tick());
     768            0 :             tuple->setBaseLen(l);
     769            0 :             tuple->setRatio(Fraction(3, 2));
     770            0 :             tuple->setTicks(l * tuple->ratio().denominator());
     771            0 :             cr->setTuplet(tuple);
     772            0 :             tuple->add(cr);
     773            0 :             tupleBeatCounter = 2;
     774              :         }
     775            5 :         elist.pop_front();
     776              :     }
     777              : 
     778            5 :     if (tick == measure->tick()) {
     779            0 :         Segment* seg = measure->getSegment(SegmentType::ChordRest, tick);
     780            0 :         auto rest = Factory::createRest(seg);
     781            0 :         rest->setTrack(staff * VOICES);
     782            0 :         auto ts = measure->timesig();
     783            0 :         rest->setTicks(ts);
     784            0 :         rest->setDurationType(TDuration(ts));
     785            0 :         seg->add(rest);
     786              :     }
     787            5 : }
     788              : 
     789            3 : void PowerTab::addToScore(ptSection& sec)
     790              : {
     791            3 :     cur_section = &sec;
     792            3 :     Fraction tick = score->lastMeasure() ? score->lastMeasure()->endTick() : Fraction(0, 1);
     793              : 
     794            3 :     Fraction lastTS(-1, -1);
     795            3 :     bool firstMeasure = true;
     796            3 :     if (score->lastMeasure()) {
     797            0 :         lastTS = score->lastMeasure()->timesig();
     798            0 :         firstMeasure = false;
     799              :     }
     800            3 :     if (firstMeasure) {
     801              :         //int lastStaff = sec.staffMap.back() + 1;
     802            8 :         for (int i = 0; i < staves; ++i) {
     803            5 :             Part* part = new Part(score);
     804            5 :             Staff* s = Factory::createStaff(part);
     805            5 :             auto info = &curTrack->infos[i];
     806            5 :             std::string ss = info->name;
     807            5 :             String staffName;
     808            5 :             if (muse::UtfCodec::isValidUtf8(ss)) {
     809            5 :                 staffName = muse::String::fromStdString(ss);
     810              :             } else {
     811              :                 // invalid utf most likely windows-125x used
     812            0 :                 std::string n = "part " + std::to_string(i + 1);
     813            0 :                 staffName = muse::String::fromStdString(n);
     814            0 :             }
     815            5 :             part->setPlainLongName(staffName);
     816              : 
     817            5 :             std::vector<int> reverseStr;
     818           25 :             for (auto it = info->strings.rbegin(); it != info->strings.rend(); ++it) {
     819           20 :                 reverseStr.push_back(*it);
     820              :             }
     821            5 :             StringData stringData(32, int(info->strings.size()), reverseStr.data());
     822            5 :             part->instrument()->setStringData(stringData);
     823              : 
     824            5 :             part->setMidiProgram(info->instrument);
     825            5 :             part->setMidiChannel(info->number);
     826              : 
     827            5 :             score->appendStaff(s);
     828            5 :             score->appendPart(part);
     829            5 :         }
     830              :     }
     831            3 :     auto bar1 = sec.bars.front();
     832            3 :     while (bar1->denominator == 0) {
     833            0 :         if (sec.bars.size() == 1) {
     834            0 :             break;
     835              :         }
     836            0 :         sec.bars.pop_front();
     837            0 :         bar1 = sec.bars.front();
     838              :     }
     839            3 :     if (bar1->denominator == 0) {
     840            0 :         bar1->denominator = 4;
     841            0 :         bar1->numerator = 4;
     842              :     }
     843            3 :     auto measure = createMeasure(bar1.get(), tick);
     844            3 :     if (repeatCount) {
     845            0 :         measure->setRepeatEnd(true);
     846            0 :         measure->setRepeatCount(repeatCount);
     847              :     }
     848            3 :     repeatCount = bar1->repeatClose;
     849            3 :     if (bar1->repeatStart) {
     850            0 :         measure->setRepeatStart(true);
     851              :     }
     852            3 :     if (sec.bars.size() > 1) {
     853            3 :         sec.bars.pop_front();
     854              :     }
     855            3 :     if (sec.tempo) {
     856            0 :         Segment* segment = measure->getSegment(SegmentType::ChordRest, measure->tick());
     857            0 :         TempoText* tt = new TempoText(segment);
     858            0 :         tt->setTempo(double(sec.tempo) / 60.0f);
     859            0 :         tt->setXmlText(String(u"<sym>metNoteQuarterUp</sym> = %1").arg(sec.tempo));
     860            0 :         tt->setTrack(0);
     861            0 :         segment->add(tt);
     862              :     }
     863            3 :     if (!sec.partName.empty() && lastPart != sec.partMarker) {
     864            0 :         lastPart = sec.partMarker;
     865            0 :         auto seg = measure->getSegment(SegmentType::ChordRest, measure->tick());
     866            0 :         RehearsalMark* t = new RehearsalMark(seg);
     867            0 :         t->setFrameType(FrameType::RECTANGLE);
     868            0 :         t->setPlainText(String(Char::fromAscii(sec.partMarker)));
     869            0 :         t->setTrack(0);
     870            0 :         seg->add(t);
     871              : 
     872            0 :         t = new RehearsalMark(seg);
     873            0 :         t->setFrameType(FrameType::NO_FRAME);
     874            0 :         std::string valid;
     875            0 :         muse::UtfCodec::replaceInvalid(sec.partName, valid);
     876            0 :         t->setPlainText(String::fromStdString(valid));
     877            0 :         t->setOffset(PointF(10.0, 0.0));
     878            0 :         t->setTrack(0);
     879            0 :         seg->add(t);
     880            0 :     }
     881            3 :     if (firstMeasure) {
     882            8 :         for (int staffIdx = 0; staffIdx < staves; ++staffIdx) {
     883            5 :             int keysig = staffIdx >= staffInc ? 0 : 1;       // Can be parsed int beat section
     884            5 :             Segment* s = measure->getSegment(SegmentType::KeySig, tick);
     885            5 :             KeySig* t = Factory::createKeySig(s);
     886            5 :             t->setKey(Key(keysig));
     887            5 :             t->setTrack(staffIdx * VOICES);
     888            5 :             s->add(t);
     889              : 
     890            5 :             ClefType clefId = staffIdx >= staffInc ? ClefType::F8_VB : ClefType::G15_MB;
     891            5 :             s = measure->getSegment(SegmentType::HeaderClef, Fraction(0, 1));
     892            5 :             auto clef = Factory::createClef(s);
     893            5 :             clef->setTrack(staffIdx * VOICES);
     894            5 :             clef->setClefType(clefId);
     895            5 :             s->add(clef);
     896              :         }
     897              :     }
     898              : 
     899            3 :     std::vector<std::vector<Note*> > tiedNotes(staves);
     900            8 :     for (auto& nvec : tiedNotes) {
     901            5 :         nvec.resize(10);
     902            5 :         memset(nvec.data(), 0, sizeof(Note*) * 10);
     903              :     }
     904              : 
     905            3 :     if (sec.beats.size() > static_cast<size_t>(staves)) {
     906            0 :         LOGE() << "Found more beat lists than staves, some beat lists will be skipped";
     907              :     }
     908              : 
     909              :     //std::vector<tBeatList>
     910              :     while (true) {
     911            3 :         bool empty = true;
     912            3 :         while (int(sec.beats.size()) < staves) {
     913            0 :             sec.beats.push_back({});
     914              :         }
     915            8 :         for (unsigned int i = 0; i < sec.beats.size() && i < tiedNotes.size(); ++i) {
     916            5 :             fillMeasure(sec.beats[i], measure, i, tiedNotes[i]);
     917            5 :             if (sec.beats[i].size() && i < unsigned(staffInc)) {
     918            0 :                 empty = false;
     919              :             }
     920              :         }
     921            3 :         if (lastTS != measure->timesig()) {
     922            0 :             lastTS = measure->timesig();
     923            0 :             for (int staffIdx = 0; staffIdx < staves; ++staffIdx) {
     924            0 :                 Staff* staff = score->staff(staffIdx);
     925            0 :                 auto staffType = staff->staffType(Fraction(0, 1));
     926            0 :                 if (staffType->genTimesig()) {
     927            0 :                     Segment* s = measure->getSegment(SegmentType::TimeSig, measure->tick());
     928            0 :                     auto t = Factory::createTimeSig(s);
     929            0 :                     t->setTrack(staffIdx * VOICES);
     930            0 :                     t->setSig(lastTS);
     931            0 :                     s->add(t);
     932              :                 }
     933              :             }
     934              :         }
     935            3 :         if (empty) {
     936            3 :             break;
     937              :         }
     938            0 :         auto bar = sec.bars.front();
     939            0 :         while (bar->denominator == 0) {
     940            0 :             if (sec.bars.size() == 1) {
     941            0 :                 break;
     942              :             }
     943            0 :             sec.bars.pop_front();
     944            0 :             bar = sec.bars.front();
     945              :         }
     946            0 :         if (bar->denominator == 0) {
     947            0 :             bar->denominator = measure->timesig().denominator();
     948            0 :             bar->numerator = measure->timesig().numerator();
     949              :         }
     950            0 :         measure = createMeasure(bar.get(), measure->endTick());
     951            0 :         if (repeatCount) {
     952            0 :             measure->setRepeatEnd(true);
     953            0 :             measure->setRepeatCount(repeatCount);
     954              :         }
     955            0 :         repeatCount = bar->repeatClose;
     956            0 :         if (bar->repeatStart) {
     957            0 :             measure->setRepeatStart(true);
     958              :         }
     959            0 :         if (sec.bars.size() > 2) {
     960            0 :             sec.bars.pop_front();
     961              :         }
     962            0 :     }
     963            3 :     if (sec.bars.size()) {
     964            3 :         auto bar = sec.bars.back();
     965            3 :         if (bar->repeatStart) {
     966            0 :             measure->setRepeatStart(true);
     967              :         }
     968            3 :         if (bar->repeatClose) {
     969            0 :             measure->setRepeatEnd(true);
     970            0 :             measure->setRepeatCount(bar->repeatClose);
     971              :         }
     972            3 :         sec.bars.clear();
     973            3 :     }
     974            3 : }
     975              : 
     976            6 : void PowerTab::ptSection::copyTracks(ptTrack* track)
     977              : {
     978              :     //if not found GuitarIn in section or all tracks are read -> return
     979            6 :     if (staves == int(staffMap.size())) {
     980            6 :         return;
     981              :     }
     982              : 
     983            0 :     auto signature = chordTextMap.begin();
     984            0 :     for (unsigned index = 0; index < staffMap.size(); ++index) {
     985            0 :         auto staff = (staffMap[index] + 1) * -1;
     986            0 :         if (staff < 0) {
     987            0 :             continue;
     988              :         }
     989              : 
     990            0 :         for (const auto& rt : rhythm) {
     991            0 :             auto newSig = chordTextMap.find(rt.position);
     992            0 :             if (newSig != chordTextMap.end()) {
     993            0 :                 signature = newSig;
     994              :             }
     995              : 
     996            0 :             ptBeat beat = ptBeat(staff, 0);
     997            0 :             beat.position = rt.position;
     998            0 :             beat.duration = rt.duration;
     999            0 :             beat.dotted = rt.dotted;
    1000            0 :             beat.doubleDotted = rt.doubleDotted;
    1001            0 :             beat.isRest = rt.is_rest;
    1002            0 :             beat.tuplet = rt.triplet;
    1003            0 :             if (!rt.is_rest) {
    1004            0 :                 auto diagram = track->diagramMap.find({ { signature->second.key, signature->second.formula,
    1005            0 :                                                           signature->second.formula_mod } });
    1006              : 
    1007            0 :                 if (diagram != track->diagramMap.end()) {
    1008            0 :                     for (unsigned int string = 0; string < diagram->second.frets.size(); ++string) {
    1009            0 :                         int fret = diagram->second.frets[string];
    1010            0 :                         if (fret >= 0xFE) {
    1011            0 :                             continue;
    1012              :                         }
    1013            0 :                         ptNote note;
    1014            0 :                         note.value = fret;
    1015            0 :                         note.str = string;
    1016            0 :                         if (fret == 0xFE) {
    1017            0 :                             note.dead = true;
    1018            0 :                             note.value = 0;
    1019              :                         }
    1020            0 :                         beat.notes.emplace_back(note);
    1021            0 :                     }
    1022              :                 } else {
    1023            0 :                     LOGD() << "diagram wasn't found";
    1024              :                 }
    1025              :             }
    1026            0 :             while (int(beats.size()) <= staff) {
    1027            0 :                 beats.push_back({});
    1028              :             }
    1029            0 :             beats[staff].push_back(beat);
    1030            0 :         }
    1031              :     }
    1032              : }
    1033              : 
    1034            6 : void PowerTab::readSection(ptSection& sec)
    1035              : {
    1036              :     //rect:
    1037            6 :     readInt();   // left
    1038            6 :     readInt();   // top
    1039            6 :     readInt();   // right
    1040            6 :     readInt();   // bottom
    1041              : 
    1042            6 :     auto lastBarData = readUInt8();
    1043              : 
    1044            6 :     skip(4);   //spacing from staff
    1045              : 
    1046            6 :     readBarLine(sec);
    1047              : 
    1048            6 :     int itemCount = readHeaderItems();
    1049            6 :     for (int i = 0; i < itemCount; ++i) {
    1050            0 :         readDirection(sec);
    1051            0 :         if (i < itemCount - 1) {
    1052            0 :             readShort();
    1053              :         }
    1054              :     }
    1055              :     //ChordText section
    1056            6 :     itemCount = readHeaderItems();
    1057            6 :     for (int i = 0; i < itemCount; ++i) {
    1058            0 :         readChordText(sec);
    1059            0 :         if (i < itemCount - 1) {
    1060            0 :             readShort();
    1061              :         }
    1062              :     }
    1063              :     //RhytmSlash
    1064            6 :     itemCount = readHeaderItems();
    1065            6 :     for (int i = 0; i < itemCount; ++i) {
    1066            0 :         readRhytmSlash(sec);
    1067            0 :         if (i < itemCount - 1) {
    1068            0 :             readShort();
    1069              :         }
    1070              :     }
    1071              :     // Staff
    1072            6 :     sec.staves = readHeaderItems();
    1073            6 :     sec.staffMap = getStaffMap(sec);
    1074           12 :     for (int i = 0; i < sec.staves; ++i) {
    1075            6 :         int staff = sec.staffMap[i];
    1076            6 :         readStaff(staff, sec);
    1077            6 :         if (i < sec.staves - 1) {
    1078            0 :             readShort();
    1079              :         }
    1080              :     }
    1081            6 :     sec.copyTracks(curTrack);
    1082              :     // MusicBar section
    1083            6 :     itemCount = readHeaderItems();
    1084            6 :     for (int i = 0; i < itemCount; ++i) {
    1085            0 :         readBarLine(sec);
    1086            0 :         if (i < itemCount - 1) {
    1087            0 :             readShort();
    1088              :         }
    1089              :     }
    1090              : 
    1091            6 :     auto bar = new ptBar();
    1092            6 :     bar->repeatClose = (lastBarData >> 5 == 4) ? lastBarData - 128 : 0;
    1093            6 :     sec.bars.push_back(std::shared_ptr<ptBar>(bar));
    1094              :     //sec.getPosition(sec.getNextPositionNumber()).addComponent(bar);
    1095            6 : }
    1096              : 
    1097            0 : void PowerTab::readDirection(ptSection& sec)
    1098              : {
    1099            0 :     int position = readUInt8();
    1100            0 :     int symbolCount = readUInt8();
    1101            0 :     for (int i = 0; i < symbolCount; ++i) {
    1102            0 :         unsigned int data = readShort();
    1103            0 :         sec.getPosition(position).addComponent(new ptDirection((data >> 8), ((data & 0xC0) >> 6), (data & 0x1F)));
    1104              :     }
    1105            0 : }
    1106              : 
    1107            6 : void PowerTab::readDataInstruments(ptTrack& info)
    1108              : {
    1109            6 :     curTrack = &info;
    1110              :     //Guitar section
    1111            6 :     auto itemCount = readHeaderItems();
    1112           11 :     for (int i = 0; i < itemCount; ++i) {
    1113            5 :         readTrackInfo(info);
    1114            5 :         if (i < itemCount - 1) {
    1115            0 :             readShort();
    1116              :         }
    1117              :     }
    1118              :     // Chord Diagram Section
    1119            6 :     itemCount = readHeaderItems();
    1120            6 :     for (int i = 0; i < itemCount; ++i) {
    1121            0 :         readChord(info);
    1122            0 :         if (i < itemCount - 1) {
    1123            0 :             readShort();
    1124              :         }
    1125              :     }
    1126              :     //Floating Text section
    1127            6 :     itemCount = readHeaderItems();
    1128            6 :     for (int i = 0; i < itemCount; ++i) {
    1129            0 :         readFloatingText();
    1130            0 :         if (i < itemCount - 1) {
    1131            0 :             readShort();
    1132              :         }
    1133              :     }
    1134              :     // GuitarIn section
    1135            6 :     itemCount = readHeaderItems();
    1136            6 :     for (int i = 0; i < itemCount; ++i) {
    1137            0 :         readGuitarIn(info);
    1138            0 :         if (i < itemCount - 1) {
    1139            0 :             readShort();
    1140              :         }
    1141              :     }
    1142              :     // Tempo marker
    1143            6 :     itemCount = readHeaderItems();
    1144            6 :     for (int i = 0; i < itemCount; ++i) {
    1145            0 :         readTempoMarker(info);
    1146            0 :         if (i < itemCount - 1) {
    1147            0 :             readShort();
    1148              :         }
    1149              :     }
    1150              :     //Dynamic section
    1151            6 :     itemCount = readHeaderItems();
    1152            6 :     for (int i = 0; i < itemCount; ++i) {
    1153            0 :         readDynamic();
    1154            0 :         if (i < itemCount - 1) {
    1155            0 :             readShort();
    1156              :         }
    1157              :     }
    1158              :     //Symbol section
    1159            6 :     itemCount = readHeaderItems();
    1160            6 :     for (int i = 0; i < itemCount; ++i) {
    1161            0 :         readSectionSymbol(info);
    1162            0 :         if (i < itemCount - 1) {
    1163            0 :             readShort();
    1164              :         }
    1165              :     }
    1166              :     //Section section
    1167            6 :     itemCount = readHeaderItems();
    1168           12 :     for (int i = 0; i < itemCount; ++i) {
    1169            6 :         readSection(info.getSection(i));
    1170            6 :         if (i < itemCount - 1) {
    1171            0 :             readShort();
    1172              :         }
    1173              :     }
    1174            6 : }
    1175              : 
    1176            0 : std::string crTS(int strings, int tuning[])
    1177              : {
    1178              :     const static char* tune[] = { "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B" };
    1179            0 :     std::vector<int> pitch;
    1180            0 :     for (int i = 0; i < strings; ++i) {
    1181            0 :         pitch.push_back(tuning[i]);
    1182              :     }
    1183            0 :     std::string t;
    1184            0 :     for (auto i : pitch) {
    1185            0 :         t += tune[i % 12];
    1186            0 :         t += " ";
    1187              :     }
    1188            0 :     return t;
    1189            0 : }
    1190              : 
    1191            3 : Measure* PowerTab::createMeasure(ptBar* bar, const Fraction& tick)
    1192              : {
    1193            3 :     auto measure = Factory::createMeasure(score);
    1194            3 :     Fraction nts(bar->numerator, bar->denominator);
    1195              : 
    1196            3 :     measure->setTick(tick);
    1197            3 :     measure->setTimesig(nts);
    1198            3 :     measure->setTicks(nts);
    1199              : 
    1200            3 :     score->measures()->append(measure);
    1201              : 
    1202            3 :     return measure;
    1203              : }
    1204              : 
    1205            6 : PowerTab::ptSection& PowerTab::ptTrack::getSection(int ind)
    1206              : {
    1207            9 :     for (int i = (int)sections.size(); i < ind + 1; ++i) {
    1208            3 :         sections.push_back(ptSection(i));
    1209              :     }
    1210            6 :     return sections[ind];
    1211              : }
    1212              : 
    1213            3 : PowerTab::ptSection::ptSection(int num)
    1214              : {
    1215            3 :     number = num;
    1216            3 : }
    1217              : 
    1218            0 : PowerTab::ptPosition& PowerTab::ptSection::getPosition(int pos)
    1219              : {
    1220            0 :     unsigned int i = 0;
    1221            0 :     while (i < positions.size()) {
    1222            0 :         auto& p = positions[i];
    1223            0 :         if (p.position == pos) {
    1224            0 :             return p;
    1225              :         }
    1226            0 :         ++i;
    1227              :     }
    1228            0 :     ptPosition p;
    1229            0 :     p.position = pos;
    1230            0 :     positions.emplace_back(p);
    1231            0 :     return positions.back();
    1232            0 : }
    1233              : 
    1234            0 : int PowerTab::ptSection::getNextPositionNumber()
    1235              : {
    1236            0 :     int next = 0;
    1237            0 :     unsigned int k = 0;
    1238            0 :     while (k < positions.size()) {
    1239            0 :         auto p = positions[k];
    1240            0 :         next = std::max(next, p.position + 1);
    1241            0 :         ++k;
    1242            0 :     }
    1243            0 :     return next;
    1244              : }
    1245              : 
    1246            0 : void PowerTab::ptPosition::addComponent(ptComponent* c)
    1247              : {
    1248            0 :     components.push_back(std::shared_ptr<ptComponent>(c));
    1249            0 : }
    1250              : 
    1251              : //---------------------------------------------------------
    1252              : //   read
    1253              : //---------------------------------------------------------
    1254              : 
    1255            3 : Err PowerTab::read()
    1256              : {
    1257            3 :     if (!readVersion()) {
    1258            0 :         return Err::FileBadFormat;
    1259              :     }
    1260            3 :     ptSong song;
    1261              : 
    1262            3 :     readSongInfo(song.info);
    1263            3 :     readDataInstruments(song.track1);
    1264            3 :     staffInc = int(song.track1.infos.size());
    1265            3 :     lastStaffMap.clear();
    1266            3 :     readDataInstruments(song.track1);
    1267              : 
    1268            3 :     staves = int(song.track1.infos.size());
    1269              : 
    1270            3 :     std::vector<tBeatList> parts(staves);
    1271            5 :     for (int i = staffInc; i < staves; ++i) {
    1272            4 :         for (auto& sec : song.track1.sections) {
    1273            2 :             while (int(sec.beats.size()) < staves) {
    1274            0 :                 sec.beats.push_back({});
    1275              :             }
    1276            2 :             parts[i].insert(parts[i].end(), sec.beats[i].begin(), sec.beats[i].end());
    1277            2 :             sec.beats[i].clear();
    1278              :         }
    1279              :     }
    1280              : 
    1281            6 :     for (auto& sec : song.track1.sections) {
    1282            8 :         for (int i = 0; i < staves; ++i) {
    1283            5 :             if (parts[i].size()) {
    1284            2 :                 sec.beats[i].insert(sec.beats[i].begin(), parts[i].begin(), parts[i].end());
    1285            2 :                 parts[i].clear();
    1286              :             }
    1287              :         }
    1288            3 :         addToScore(sec);
    1289            8 :         for (int i = 0; i < staves; ++i) {
    1290            5 :             parts[i] = sec.beats[i];
    1291              :         }
    1292              :     }
    1293              : 
    1294              :     MeasureBase* m;
    1295            3 :     if (!score->measures()->first()) {
    1296            0 :         m = Factory::createTitleVBox(score);
    1297            0 :         score->measures()->append(m);
    1298              :     } else {
    1299            3 :         m = score->measures()->first();
    1300            3 :         if (!m->isVBox()) {
    1301            3 :             MeasureBase* mb = Factory::createTitleVBox(score);
    1302            3 :             score->addMeasure(mb, m);
    1303            3 :             m = mb;
    1304              :         }
    1305              :     }
    1306              :     // create title
    1307            3 :     std::string name = song.info.name;
    1308            3 :     if (!name.empty()) {
    1309            0 :         Text* s = Factory::createText(m, TextStyleType::TITLE);
    1310            0 :         std::string valid;
    1311            0 :         muse::UtfCodec::replaceInvalid(name, valid);
    1312            0 :         s->setPlainText(String::fromStdString(valid));
    1313            0 :         m->add(s);
    1314            0 :     }
    1315            3 :     return Err::NoError;
    1316            3 : }
    1317              : } // namespace mu::iex::guitarpro
        

Generated by: LCOV version 2.0-1