LCOV - code coverage report
Current view: top level - src/importexport/musedata/internal - musedata.cpp Coverage Total Hit
Test: filtered_coverage.info Lines: 0.0 % 466 0
Test Date: 2026-11-05 04:07:02

            Line data    Source code
       1              : /*
       2              :  * SPDX-License-Identifier: GPL-3.0-only
       3              :  * MuseScore-Studio-CLA-applies
       4              :  *
       5              :  * MuseScore Studio
       6              :  * Music Composition & Notation
       7              :  *
       8              :  * Copyright (C) 2021 MuseScore Limited and others
       9              :  *
      10              :  * This program is free software: you can redistribute it and/or modify
      11              :  * it under the terms of the GNU General Public License version 3 as
      12              :  * published by the Free Software Foundation.
      13              :  *
      14              :  * This program is distributed in the hope that it will be useful,
      15              :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      16              :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      17              :  * GNU General Public License for more details.
      18              :  *
      19              :  * You should have received a copy of the GNU General Public License
      20              :  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
      21              :  */
      22              : 
      23              : #include "musedata.h"
      24              : 
      25              : #include <QFile>
      26              : 
      27              : #include "engraving/dom/articulation.h"
      28              : #include "engraving/dom/barline.h"
      29              : #include "engraving/dom/bracket.h"
      30              : #include "engraving/dom/chord.h"
      31              : #include "engraving/dom/clef.h"
      32              : #include "engraving/dom/dynamic.h"
      33              : #include "engraving/dom/factory.h"
      34              : #include "engraving/dom/key.h"
      35              : #include "engraving/dom/lyrics.h"
      36              : #include "engraving/dom/masterscore.h"
      37              : #include "engraving/dom/measure.h"
      38              : #include "engraving/dom/note.h"
      39              : #include "engraving/dom/part.h"
      40              : #include "engraving/dom/rest.h"
      41              : #include "engraving/dom/segment.h"
      42              : #include "engraving/dom/slur.h"
      43              : #include "engraving/dom/staff.h"
      44              : #include "engraving/dom/timesig.h"
      45              : #include "engraving/dom/tuplet.h"
      46              : #include "engraving/editing/editstaffbrackets.h"
      47              : #include "engraving/editing/transpose.h"
      48              : 
      49              : #include "log.h"
      50              : 
      51              : using namespace mu::iex::musedata;
      52              : using namespace mu::engraving;
      53              : 
      54              : //---------------------------------------------------------
      55              : //   musicalAttribute
      56              : //---------------------------------------------------------
      57              : 
      58            0 : void MuseData::musicalAttribute(QStringView s, Part* part)
      59              : {
      60            0 :     QList<QStringView> al = s.mid(2).split(u' ', Qt::SkipEmptyParts);
      61            0 :     foreach (QStringView item, al) {
      62            0 :         if (item.startsWith(u"K:")) {
      63            0 :             Key key = Key(item.mid(2).toInt());
      64            0 :             KeySigEvent ke;
      65            0 :             Interval v = part->instrument(curTick)->transpose();
      66            0 :             ke.setConcertKey(key);
      67            0 :             if (!v.isZero() && !score->style().styleB(Sid::concertPitch)) {
      68            0 :                 v.flip();
      69            0 :                 ke.setKey(Transpose::transposeKey(key, v));
      70              :             }
      71            0 :             for (Staff* staff : part->staves()) {
      72            0 :                 staff->setKey(curTick, ke);
      73              :             }
      74            0 :         } else if (item.startsWith(u"Q:")) {
      75            0 :             _division = item.mid(2).toInt();
      76            0 :         } else if (item.startsWith(u"T:")) {
      77            0 :             QList<QStringView> tl = item.mid(2).split(u'/');
      78            0 :             if (tl.size() != 2) {
      79            0 :                 LOGD() << "bad time sig: " << item;
      80            0 :                 continue;
      81              :             }
      82            0 :             int z = tl[0].toInt();
      83            0 :             int n = tl[1].toInt();
      84            0 :             if ((z > 0) && (n > 0)) {
      85            0 :                 Measure* mes = score->tick2measure(curTick);
      86            0 :                 Segment* seg = mes->getSegment(SegmentType::TimeSig, curTick);
      87            0 :                 TimeSig* ts = Factory::createTimeSig(seg);
      88            0 :                 Staff* staff = part->staff(0);
      89            0 :                 ts->setTrack(staff->idx() * VOICES);
      90            0 :                 ts->setSig(Fraction(z, n));
      91            0 :                 seg->add(ts);
      92              :             }
      93            0 :         } else if (item.startsWith(u"X:")) {
      94            0 :         } else if (item[0] == 'C') {
      95            0 :             int staffIdx = 1;
      96            0 :             int col = 2;
      97            0 :             if (item[1].isDigit()) {
      98            0 :                 staffIdx = item.mid(1, 1).toInt();
      99            0 :                 col = 3;
     100              :             }
     101            0 :             staffIdx -= 1;
     102            0 :             int clefCode = item.mid(col).toInt();
     103            0 :             ClefType clefType = ClefType::G;
     104            0 :             switch (clefCode) {
     105              :             // G clef
     106            0 :             case 04: clefType = ClefType::G;
     107            0 :                 break;
     108            0 :             case 05: clefType = ClefType::G_1;
     109            0 :                 break;
     110              : 
     111              :             // C clef
     112            0 :             case 11: clefType = ClefType::C5;
     113            0 :                 break;
     114            0 :             case 12: clefType = ClefType::C4;
     115            0 :                 break;
     116            0 :             case 13: clefType = ClefType::C3;
     117            0 :                 break;
     118            0 :             case 14: clefType = ClefType::C2;
     119            0 :                 break;
     120            0 :             case 15: clefType = ClefType::C1;
     121            0 :                 break;
     122              : 
     123              :             // F clef
     124            0 :             case 21: clefType = ClefType::F_C;
     125            0 :                 break;
     126            0 :             case 22: clefType = ClefType::F;
     127            0 :                 break;
     128            0 :             case 23: clefType = ClefType::F_B;
     129            0 :                 break;
     130              : 
     131              :             // G clef 8vb
     132            0 :             case 34: clefType = ClefType::G8_VB;
     133            0 :                 break;
     134              : 
     135              :             // F clef 8vb
     136            0 :             case 52: clefType = ClefType::F8_VB;
     137            0 :                 break;
     138              : 
     139              :             // G clef 8va
     140            0 :             case 64: clefType = ClefType::G8_VA;
     141            0 :                 break;
     142              : 
     143              :             // F clef 8va
     144            0 :             case 82: clefType = ClefType::F_8VA;
     145            0 :                 break;
     146              : 
     147            0 :             default:
     148            0 :                 LOGD() << "unknown clef code: " << clefCode;
     149            0 :                 break;
     150              :             }
     151              : 
     152            0 :             Measure* mes = score->tick2measure(curTick);
     153            0 :             Segment* seg = mes->getSegment(SegmentType::Clef, curTick);
     154            0 :             Staff* staff = part->staff(staffIdx);
     155            0 :             Clef* clef = Factory::createClef(seg);
     156            0 :             clef->setTrack(staff->idx() * VOICES);
     157            0 :             clef->setClefType(clefType);
     158            0 :             seg->add(clef);
     159              :         } else {
     160            0 :             LOGD() << "unknown $key: " << item;
     161              :         }
     162            0 :     }
     163            0 : }
     164              : 
     165              : //---------------------------------------------------------
     166              : //   readChord
     167              : //---------------------------------------------------------
     168              : 
     169            0 : void MuseData::readChord(Part*, QStringView s)
     170              : {
     171              :     //                       a  b   c  d  e  f  g
     172              :     static int table[7]  = { 9, 11, 0, 2, 4, 5, 7 };
     173              : 
     174            0 :     int step  = s[1].toLatin1() - 'A';
     175            0 :     int alter = 0;
     176            0 :     int octave = 0;
     177            0 :     for (int i = 2; i < 4; ++i) {
     178            0 :         if (s[i] == '#') {
     179            0 :             alter += 1;
     180            0 :         } else if (s[i] == 'f') {
     181            0 :             alter -= 1;
     182            0 :         } else if (s[i].isDigit()) {
     183            0 :             octave = s.mid(i, 1).toInt();
     184            0 :             break;
     185              :         }
     186              :     }
     187            0 :     int staffIdx = 0;
     188            0 :     if (s.size() >= 24) {
     189            0 :         if (s[23].isDigit()) {
     190            0 :             staffIdx = s.mid(23, 1).toInt() - 1;
     191              :         }
     192              :     }
     193            0 :     int pitch = clampPitch(table[step] + alter + (octave + 1) * 12);
     194              : 
     195            0 :     Chord* chord = (Chord*)chordRest;
     196            0 :     Note* note = Factory::createNote(chord);
     197            0 :     note->setPitch(pitch);
     198            0 :     note->setTpcFromPitch();
     199            0 :     note->setTrack(staffIdx * VOICES + voice);
     200            0 :     chord->add(note);
     201            0 : }
     202              : 
     203              : //---------------------------------------------------------
     204              : //   openSlur
     205              : //---------------------------------------------------------
     206              : 
     207            0 : void MuseData::openSlur(int idx, const Fraction& tick, Staff* staff, int voc, EngravingItem* startChord)
     208              : {
     209            0 :     staff_idx_t staffIdx = staff->idx();
     210            0 :     if (slur[idx]) {
     211            0 :         LOGD("%06d: slur %d already open", tick.ticks(), idx + 1);
     212            0 :         return;
     213              :     }
     214            0 :     slur[idx] = Factory::createSlur(score->dummy());
     215            0 :     slur[idx]->setTick(tick);
     216            0 :     slur[idx]->setTrack(staffIdx * VOICES + voc);
     217            0 :     slur[idx]->setStartElement(startChord);
     218            0 :     score->addElement(slur[idx]);
     219              : }
     220              : 
     221              : //---------------------------------------------------------
     222              : //   closeSlur
     223              : //---------------------------------------------------------
     224              : 
     225            0 : void MuseData::closeSlur(int idx, const Fraction& tick, Staff* staff, int voc, engraving::EngravingItem* endChord)
     226              : {
     227            0 :     staff_idx_t staffIdx = staff->idx();
     228            0 :     if (slur[idx]) {
     229            0 :         slur[idx]->setTick2(tick);
     230            0 :         slur[idx]->setTrack2(staffIdx * VOICES + voc);
     231            0 :         slur[idx]->setEndElement(endChord);
     232            0 :         slur[idx] = 0;
     233              :     } else {
     234            0 :         LOGD("%06d: slur %d not open", tick.ticks(), idx + 1);
     235              :     }
     236            0 : }
     237              : 
     238              : //---------------------------------------------------------
     239              : //   readNote
     240              : //---------------------------------------------------------
     241              : 
     242            0 : void MuseData::readNote(Part* part, QStringView s)
     243              : {
     244              :     //                       a  b   c  d  e  f  g
     245              :     static int table[7]  = { 9, 11, 0, 2, 4, 5, 7 };
     246              : 
     247            0 :     int step  = s[0].toLatin1() - 'A';
     248            0 :     int alter = 0;
     249            0 :     int octave = 0;
     250            0 :     for (int i = 1; i < 3; ++i) {
     251            0 :         if (s[i] == '#') {
     252            0 :             alter += 1;
     253            0 :         } else if (s[i] == 'f') {
     254            0 :             alter -= 1;
     255            0 :         } else if (s[i].isDigit()) {
     256            0 :             octave = s.mid(i, 1).toInt();
     257            0 :             break;
     258              :         }
     259              :     }
     260            0 :     DirectionV dir = DirectionV::AUTO;
     261            0 :     if (s.size() >= 23) {
     262            0 :         if (s[22] == 'u') {
     263            0 :             dir = DirectionV::UP;
     264            0 :         } else if (s[22] == 'd') {
     265            0 :             dir = DirectionV::DOWN;
     266              :         }
     267              :     }
     268              : 
     269            0 :     int staffIdx = 0;
     270            0 :     if (s.size() >= 24) {
     271            0 :         if (s[23].isDigit()) {
     272            0 :             staffIdx = s.mid(23, 1).toInt() - 1;
     273              :         }
     274              :     }
     275            0 :     Staff* staff = part->staff(staffIdx);
     276            0 :     staff_idx_t gstaff = staff->idx();
     277              : 
     278            0 :     int pitch = table[step] + alter + (octave + 1) * 12;
     279            0 :     if (pitch < 0) {
     280            0 :         pitch = 0;
     281              :     }
     282            0 :     if (pitch > 127) {
     283            0 :         pitch = 127;
     284              :     }
     285            0 :     Fraction ticks = Fraction::fromTicks((s.mid(5, 3).toInt() * Constants::DIVISION + _division / 2) / _division);
     286            0 :     Fraction tick  = curTick;
     287            0 :     curTick  += ticks;
     288              : 
     289            0 :     Tuplet* tuplet = 0;
     290            0 :     if (s.size() >= 22) {
     291            0 :         int a = 1;
     292            0 :         int b = 1;
     293            0 :         if (s[19] != ' ') {
     294            0 :             a = s[19].toLatin1() - '0';
     295            0 :             if (a == 3 && s[20] != ':') {
     296            0 :                 b = 2;
     297              :             } else {
     298            0 :                 b = s[21].toLatin1() - '0';
     299              :             }
     300              :         }
     301            0 :         if (a == 3 && b == 2) {           // triplet
     302            0 :             if (chordRest && chordRest->tuplet() && ntuplet) {
     303            0 :                 tuplet = chordRest->tuplet();
     304              :             } else {
     305            0 :                 tuplet = new Tuplet(measure);
     306            0 :                 tuplet->setTrack(gstaff * VOICES);
     307            0 :                 tuplet->setTick(tick);
     308            0 :                 ntuplet = a;
     309            0 :                 tuplet->setRatio(Fraction(a, b));
     310            0 :                 measure->add(tuplet);
     311              :             }
     312            0 :         } else if (a == 1 && b == 1) {
     313              :         } else {
     314            0 :             LOGD("unsupported tuple %d/%d", a, b);
     315              :         }
     316              :     }
     317              : 
     318            0 :     Chord* chord = Factory::createChord(score->dummy());
     319            0 :     chordRest = chord;
     320            0 :     chord->setTrack(gstaff * VOICES);
     321            0 :     chord->setStemDirection(dir);
     322            0 :     if (tuplet) {
     323            0 :         chord->setTuplet(tuplet);
     324            0 :         tuplet->add(chord);
     325            0 :         --ntuplet;
     326              :     }
     327            0 :     TDuration d;
     328            0 :     d.setVal(ticks.ticks());
     329            0 :     chord->setDurationType(d);
     330              : 
     331            0 :     Segment* segment = measure->getSegment(SegmentType::ChordRest, tick);
     332              : 
     333            0 :     voice = 0;
     334            0 :     for (; voice < static_cast<int>(VOICES); ++voice) {
     335            0 :         EngravingItem* e = segment->element(gstaff * VOICES + voice);
     336            0 :         if (e == 0) {
     337            0 :             chord->setTrack(gstaff * VOICES + voice);
     338            0 :             segment->add(chord);
     339            0 :             break;
     340              :         }
     341              :     }
     342            0 :     if (voice == VOICES) {
     343            0 :         LOGD("cannot allocate voice");
     344            0 :         delete chord;
     345            0 :         return;
     346              :     }
     347            0 :     Note* note = Factory::createNote(chord);
     348            0 :     note->setPitch(pitch);
     349            0 :     note->setTpcFromPitch();
     350            0 :     note->setTrack(gstaff * VOICES + voice);
     351            0 :     chord->add(note);
     352              : 
     353            0 :     QString dynamics;
     354            0 :     QStringView an = s.mid(31, 11);
     355            0 :     for (int i = 0; i < an.size(); ++i) {
     356            0 :         if (an[i] == '(') {
     357            0 :             openSlur(0, tick, staff, voice, chord);
     358            0 :         } else if (an[i] == ')') {
     359            0 :             closeSlur(0, tick, staff, voice, chord);
     360            0 :         } else if (an[i] == '[') {
     361            0 :             openSlur(1, tick, staff, voice, chord);
     362            0 :         } else if (an[i] == ']') {
     363            0 :             closeSlur(1, tick, staff, voice, chord);
     364            0 :         } else if (an[i] == '{') {
     365            0 :             openSlur(2, tick, staff, voice, chord);
     366            0 :         } else if (an[i] == '}') {
     367            0 :             closeSlur(2, tick, staff, voice, chord);
     368            0 :         } else if (an[i] == 'z') {
     369            0 :             openSlur(3, tick, staff, voice, chord);
     370            0 :         } else if (an[i] == 'x') {
     371            0 :             closeSlur(3, tick, staff, voice, chord);
     372            0 :         } else if (an[i] == '.') {
     373            0 :             Articulation* atr = Factory::createArticulation(chord);
     374            0 :             atr->setSymId(SymId::articStaccatoAbove);
     375            0 :             chord->add(atr);
     376            0 :         } else if (an[i] == '_') {
     377            0 :             Articulation* atr = Factory::createArticulation(chord);
     378            0 :             atr->setSymId(SymId::articTenutoAbove);
     379            0 :             chord->add(atr);
     380            0 :         } else if (an[i] == 'v') {
     381            0 :             Articulation* atr = Factory::createArticulation(chord);
     382            0 :             atr->setSymId(SymId::stringsUpBow);
     383            0 :             chord->add(atr);
     384            0 :         } else if (an[i] == 'n') {
     385            0 :             Articulation* atr = Factory::createArticulation(chord);
     386            0 :             atr->setSymId(SymId::stringsDownBow);
     387            0 :             chord->add(atr);
     388            0 :         } else if (an[i] == 't') {
     389            0 :             Articulation* atr = Factory::createArticulation(chord);
     390            0 :             atr->setSymId(SymId::ornamentTrill);
     391            0 :             chord->add(atr);
     392            0 :         } else if (an[i] == 'F') {
     393            0 :             Articulation* atr = Factory::createArticulation(chord);
     394            0 :             atr->setUp(true);
     395            0 :             atr->setSymId(SymId::fermataAbove);
     396            0 :             chord->add(atr);
     397            0 :         } else if (an[i] == 'E') {
     398            0 :             Articulation* atr = Factory::createArticulation(chord);
     399            0 :             atr->setUp(false);
     400            0 :             atr->setSymId(SymId::fermataBelow);
     401            0 :             chord->add(atr);
     402            0 :         } else if (an[i] == 'O') {
     403              :             // Articulation* atr = new Articulation(score);
     404              :             // atr->setArticulationType(ArticulationType::Downbow);
     405              :             // chord->add(atr);
     406            0 :             LOGD("%06d: open string '%c' not implemented", tick.ticks(), an[i].toLatin1());
     407            0 :         } else if (an[i] == '&') {
     408              :             // skip editorial level
     409            0 :             if (i <= an.size() && an[i + 1].isDigit()) {
     410            0 :                 ++i;
     411              :             }
     412            0 :         } else if (an[i] == 'p') {
     413            0 :             dynamics += "p";
     414            0 :         } else if (an[i] == 'm') {
     415            0 :             dynamics += "m";
     416            0 :         } else if (an[i] == 'f') {
     417            0 :             dynamics += "f";
     418            0 :         } else if (an[i] == '-') {        // tie
     419            0 :         } else if (an[i] == '*') {        // start tuplet
     420            0 :         } else if (an[i] == '!') {        // stop tuplet
     421            0 :         } else if (an[i] == '+') {        // cautionary accidental
     422            0 :         } else if (an[i] == 'X') {        // ???
     423            0 :         } else if (an[i] == ' ') {
     424              :         } else {
     425            0 :             LOGD("%06d: notation '%c' not implemented", tick.ticks(), an[i].toLatin1());
     426              :         }
     427              :     }
     428            0 :     if (!dynamics.isEmpty()) {
     429            0 :         Segment* seg = measure->getSegment(SegmentType::ChordRest, tick);
     430            0 :         Dynamic* dyn = Factory::createDynamic(seg);
     431            0 :         dyn->setDynamicType(dynamics);
     432            0 :         dyn->setTrack(gstaff * VOICES);
     433            0 :         seg->add(dyn);
     434              :     }
     435              : 
     436            0 :     QStringView txt = s.mid(43, 36);
     437            0 :     if (!txt.isEmpty()) {
     438            0 :         QList<QStringView> sl = txt.split(u'|');
     439            0 :         int no = 0;
     440            0 :         for (const QStringView w : sl) {
     441            0 :             Lyrics* l = Factory::createLyrics(chord);
     442            0 :             l->setPlainText(diacritical(w));
     443            0 :             l->setVerse(no++);
     444            0 :             l->setTrack(gstaff * VOICES);
     445            0 :             chord->add(l);
     446              :         }
     447            0 :     }
     448            0 : }
     449              : 
     450              : //---------------------------------------------------------
     451              : //   diacritical
     452              : // TODO: not complete
     453              : //---------------------------------------------------------
     454              : 
     455            0 : QString MuseData::diacritical(QStringView s)
     456              : {
     457              :     struct TAB {
     458              :         const char* a;
     459              :         const char* b;
     460            0 :     } tab[] = {
     461              :         { "\\\\", "\\" },
     462              :         { "\\2s", "ß" },
     463              :         { "\\3a", "ä" },
     464              :         { "\\3o", "ö" },
     465              :         { "\\3u", "ü" },
     466              : 
     467              :         { "\\s2", "ß" },
     468              :         { "\\a3", "ä" },
     469              :         { "\\o3", "ö" },
     470              :         { "\\u3", "ü" },
     471              :     };
     472              : 
     473            0 :     QString result = s.toString();
     474            0 :     for (unsigned int i = 0; i < sizeof(tab) / sizeof(*tab); ++i) {
     475            0 :         result = result.replace(tab[i].a, QString::fromUtf8(tab[i].b));
     476              :     }
     477            0 :     return result;
     478            0 : }
     479              : 
     480              : //---------------------------------------------------------
     481              : //   readRest
     482              : //---------------------------------------------------------
     483              : 
     484            0 : void MuseData::readRest(Part* part, QStringView s)
     485              : {
     486            0 :     Fraction ticks = Fraction::fromTicks((s.mid(5, 3).toInt() * Constants::DIVISION + _division / 2) / _division);
     487              : 
     488            0 :     Fraction tick  = curTick;
     489            0 :     curTick  += ticks;
     490              : 
     491            0 :     int staffIdx = 0;
     492            0 :     if (s.size() >= 24) {
     493            0 :         if (s[23].isDigit()) {
     494            0 :             staffIdx = s.mid(23, 1).toInt() - 1;
     495              :         }
     496              :     }
     497            0 :     Staff* staff = part->staff(staffIdx);
     498            0 :     staff_idx_t gstaff = staff->idx();
     499              : 
     500            0 :     TDuration d;
     501            0 :     d.setVal(ticks.ticks());
     502            0 :     Rest* rest = Factory::createRest(score->dummy(), d);
     503            0 :     rest->setTicks(d.fraction());
     504            0 :     chordRest  = rest;
     505            0 :     rest->setTrack(gstaff * VOICES);
     506            0 :     Segment* segment = measure->getSegment(SegmentType::ChordRest, tick);
     507              : 
     508            0 :     voice = 0;
     509            0 :     for (; voice < static_cast<int>(VOICES); ++voice) {
     510            0 :         EngravingItem* e = segment->element(gstaff * VOICES + voice);
     511            0 :         if (e == 0) {
     512            0 :             rest->setTrack(gstaff * VOICES + voice);
     513            0 :             segment->add(rest);
     514            0 :             break;
     515              :         }
     516              :     }
     517            0 :     if (voice == VOICES) {
     518            0 :         LOGD("cannot allocate voice");
     519            0 :         delete rest;
     520            0 :         return;
     521              :     }
     522              : }
     523              : 
     524              : //---------------------------------------------------------
     525              : //   readBackup
     526              : //---------------------------------------------------------
     527              : 
     528            0 : void MuseData::readBackup(QStringView s)
     529              : {
     530            0 :     Fraction ticks = Fraction::fromTicks((s.mid(5, 3).toInt() * Constants::DIVISION + _division / 2) / _division);
     531            0 :     if (s[0] == 'b') {
     532            0 :         curTick -= ticks;
     533              :     } else {
     534            0 :         curTick += ticks;
     535              :     }
     536            0 : }
     537              : 
     538              : //---------------------------------------------------------
     539              : //   createMeasure
     540              : //---------------------------------------------------------
     541              : 
     542            0 : Measure* MuseData::createMeasure()
     543              : {
     544            0 :     for (MeasureBase* mb = score->first(); mb; mb = mb->next()) {
     545            0 :         if (!mb->isMeasure()) {
     546            0 :             continue;
     547              :         }
     548            0 :         Measure* m = (Measure*)mb;
     549            0 :         Fraction st = m->tick();
     550            0 :         Fraction l  = m->ticks();
     551            0 :         if (curTick == st) {
     552            0 :             return m;
     553              :         }
     554            0 :         if (curTick > st && curTick < (st + l)) {
     555              :             // irregular measure
     556            0 :             break;
     557              :         }
     558            0 :         if (curTick < st + l) {
     559            0 :             LOGD("cannot create measure at %d", curTick.ticks());
     560            0 :             return 0;
     561              :         }
     562              :     }
     563            0 :     Measure* mes  = Factory::createMeasure(score);
     564            0 :     mes->setTick(curTick);
     565              : 
     566            0 :     score->measures()->append(mes);
     567            0 :     return mes;
     568              : }
     569              : 
     570              : //---------------------------------------------------------
     571              : //   readPart
     572              : //---------------------------------------------------------
     573              : 
     574            0 : void MuseData::readPart(const QStringList& sl, Part* part)
     575              : {
     576            0 :     int line = 10;
     577            0 :     QString s;
     578            0 :     for (; line < sl.size(); ++line) {
     579            0 :         s = sl[line];
     580            0 :         if (!s.isEmpty() && s[0] == '$') {
     581            0 :             break;
     582              :         }
     583              :     }
     584            0 :     if (line >= sl.size()) {
     585            0 :         LOGD(" $ not found in part");
     586            0 :         return;
     587              :     }
     588            0 :     curTick = Fraction(0, 1);
     589            0 :     slur[0] = 0;
     590            0 :     slur[1] = 0;
     591            0 :     slur[2] = 0;
     592            0 :     slur[3] = 0;
     593            0 :     measure = 0;
     594            0 :     measure = createMeasure();
     595            0 :     for (; line < sl.size(); ++line) {
     596            0 :         s = sl[line];
     597              : // LOGD("%6d: <%s>", curTick.ticks(), qPrintable(s));
     598            0 :         char c = s[0].toLatin1();
     599            0 :         switch (c) {
     600            0 :         case 'A':
     601              :         case 'B':
     602              :         case 'C':
     603              :         case 'D':
     604              :         case 'E':
     605              :         case 'F':
     606              :         case 'G':
     607            0 :             readNote(part, s);
     608            0 :             break;
     609            0 :         case ' ':                   // chord
     610            0 :             readChord(part, s);
     611            0 :             break;
     612            0 :         case 'r':
     613            0 :             readRest(part, s);
     614            0 :             break;
     615            0 :         case 'g':                   // grace note
     616              :         case 'c':                   // cue note
     617              :         case 'f':                   // basso continuo
     618            0 :             break;
     619            0 :         case 'b':                   // backspace
     620              :         case 'i':                   // forward space
     621            0 :             readBackup(s);
     622            0 :             break;
     623            0 :         case 'm':                   // measure line / bar line
     624            0 :             measure = createMeasure();
     625            0 :             break;
     626            0 :         case '*':                   // musical direction
     627            0 :             break;
     628            0 :         case 'P':                   // print suggestion
     629            0 :             break;
     630            0 :         case 'S':                   // sound record
     631            0 :             break;
     632            0 :         case '$':
     633            0 :             musicalAttribute(s, part);
     634            0 :             break;
     635            0 :         default:
     636            0 :             LOGD("unknown record <%s>", qPrintable(s));
     637            0 :             break;
     638              :         }
     639              :     }
     640            0 : }
     641              : 
     642              : //---------------------------------------------------------
     643              : //   countStaves
     644              : //---------------------------------------------------------
     645              : 
     646            0 : int MuseData::countStaves(const QStringList& sl)
     647              : {
     648            0 :     int staves = 1;
     649            0 :     for (int i = 10; i < sl.size(); ++i) {
     650            0 :         QStringView s { sl[i] };
     651            0 :         char c = s[0].toLatin1();
     652            0 :         switch (c) {
     653            0 :         case 'A':
     654              :         case 'B':
     655              :         case 'C':
     656              :         case 'D':
     657              :         case 'E':
     658              :         case 'F':
     659              :         case 'G':
     660              :         case 'r':
     661              :         {
     662            0 :             int staffIdx = 1;
     663            0 :             if (s.size() >= 24) {
     664            0 :                 if (s[23].isDigit()) {
     665            0 :                     staffIdx = s.mid(23, 1).toInt();
     666              :                 }
     667              :             }
     668            0 :             if (staffIdx > staves) {
     669            0 :                 staves = staffIdx;
     670              :             }
     671              :         }
     672            0 :         break;
     673              :         }
     674              :     }
     675            0 :     return staves;
     676              : }
     677              : 
     678              : //---------------------------------------------------------
     679              : //   read
     680              : //    return false on error
     681              : //---------------------------------------------------------
     682              : 
     683            0 : bool MuseData::read(const QString& name)
     684              : {
     685            0 :     QFile fp(name);
     686            0 :     if (!fp.open(QIODevice::ReadOnly)) {
     687            0 :         LOGD("Cannot open file <%s>", qPrintable(name));
     688            0 :         return false;
     689              :     }
     690            0 :     QTextStream ts(&fp);
     691            0 :     QStringList part;
     692            0 :     bool commentMode = false;
     693              :     for (;;) {
     694            0 :         QString s(ts.readLine());
     695            0 :         if (s.isNull()) {
     696            0 :             break;
     697              :         }
     698            0 :         if (s.isEmpty()) {
     699            0 :             if (!commentMode) {
     700            0 :                 part.append(QString(""));
     701              :             }
     702            0 :             continue;
     703              :         }
     704            0 :         if (s[0] == '&') {
     705            0 :             commentMode = !commentMode;
     706            0 :             continue;
     707              :         }
     708            0 :         if (commentMode) {
     709            0 :             continue;
     710              :         }
     711            0 :         if (s[0] == '@') {
     712            0 :             continue;
     713              :         }
     714            0 :         if (s[0] == '/') {
     715            0 :             parts.append(part);
     716              : 
     717            0 :             Part* mpart = new Part(score);
     718            0 :             int staves  = countStaves(part);
     719            0 :             for (int i = 0; i < staves; ++i) {
     720            0 :                 Staff* staff = Factory::createStaff(mpart);
     721            0 :                 score->appendStaff(staff);
     722              : 
     723            0 :                 if ((staves == 2) && (i == 0)) {
     724            0 :                     EditStaffBrackets::setBracketType(score, staff->idx(), 0, BracketType::BRACE);
     725            0 :                     EditStaffBrackets::setBracketSpan(score, staff->idx(), 0, 2);
     726              :                 }
     727              :             }
     728            0 :             score->appendPart(mpart);
     729            0 :             if (part.size() > 8) {
     730            0 :                 mpart->setPlainLongName(part[8]);
     731              :             }
     732            0 :             part.clear();
     733            0 :             continue;
     734            0 :         }
     735            0 :         if (s[0] == 'a') {
     736            0 :             part.back().append(s.mid(1));
     737            0 :             continue;
     738              :         }
     739            0 :         part.append(s);
     740            0 :     }
     741            0 :     fp.close();
     742            0 :     return true;
     743            0 : }
     744              : 
     745              : //---------------------------------------------------------
     746              : //   convert
     747              : //---------------------------------------------------------
     748              : 
     749            0 : void MuseData::convert()
     750              : {
     751            0 :     for (int pn = 0; pn < parts.size(); ++pn) {
     752            0 :         Part* part = (score->parts())[pn];
     753            0 :         readPart(parts[pn], part);
     754              :     }
     755            0 : }
        

Generated by: LCOV version 2.0-1