LCOV - code coverage report
Current view: top level - src/engraving/rw/read500 - measureread.cpp Coverage Total Hit
Test: filtered_coverage.info Lines: 64.2 % 424 272
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) 2026 MuseScore Limited
       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 "measureread.h"
      23              : 
      24              : #include "translation.h"
      25              : 
      26              : #include "../dom/ambitus.h"
      27              : #include "../dom/anchors.h"
      28              : #include "../dom/barline.h"
      29              : #include "../dom/beam.h"
      30              : #include "../dom/breath.h"
      31              : #include "../dom/chord.h"
      32              : #include "../dom/dynamic.h"
      33              : #include "../dom/expression.h"
      34              : #include "../dom/factory.h"
      35              : #include "../dom/fermata.h"
      36              : #include "../dom/fret.h"
      37              : #include "../dom/keysig.h"
      38              : #include "../dom/location.h"
      39              : #include "../dom/measure.h"
      40              : #include "../dom/measurenumber.h"
      41              : #include "../dom/measurerepeat.h"
      42              : #include "../dom/mmrest.h"
      43              : #include "../dom/mmrestrange.h"
      44              : #include "../dom/score.h"
      45              : #include "../dom/segment.h"
      46              : #include "../dom/spacer.h"
      47              : #include "../dom/staff.h"
      48              : #include "../dom/stafflines.h"
      49              : #include "../dom/stafftext.h"
      50              : #include "../dom/system.h"
      51              : #include "../dom/systemdivider.h"
      52              : #include "../dom/timesig.h"
      53              : #include "../dom/tuplet.h"
      54              : #include "../dom/harmony.h"
      55              : #include "../dom/fret.h"
      56              : #include "../dom/tremolobar.h"
      57              : #include "../dom/tempotext.h"
      58              : #include "../dom/image.h"
      59              : 
      60              : #include "../types/typesconv.h"
      61              : #include "tread.h"
      62              : 
      63              : #include "log.h"
      64              : 
      65              : using namespace mu::engraving;
      66              : using namespace mu::engraving::read500;
      67              : 
      68         6506 : void MeasureRead::readMeasure(Measure* measure, XmlReader& e, ReadContext& ctx, int staffIdx)
      69              : {
      70         6506 :     IF_ASSERT_FAILED(ctx.isSameScore(measure)) {
      71            0 :         return;
      72              :     }
      73              : 
      74         6506 :     ctx.setCurrentMeasure(measure);
      75         6506 :     int nextTrack = staffIdx * VOICES;
      76         6506 :     ctx.setTrack(nextTrack);
      77              : 
      78         6506 :     for (int n = int(measure->mstaves().size()); n <= staffIdx; ++n) {
      79            0 :         Staff* staff = ctx.staff(n);
      80            0 :         MStaff* s = new MStaff;
      81            0 :         s->setLines(Factory::createStaffLines(measure));
      82            0 :         s->lines()->setTrack(n * VOICES);
      83            0 :         s->lines()->setVisible(!staff->isLinesInvisible(measure->tick()));
      84            0 :         measure->mstaves().push_back(s);
      85              :     }
      86              : 
      87         6506 :     bool irregular = false;
      88         6506 :     if (e.hasAttribute("len")) {
      89           14 :         bool ok = true;
      90           14 :         measure->setTicks(Fraction::fromString(e.attribute("len"), &ok));
      91           14 :         if (!ok || measure->ticks() < Fraction(1, 128)) {
      92            0 :             e.raiseError(muse::mtrc("engraving", "MSCX error at byte offset %1: invalid measure length: %2")
      93            0 :                          .arg(e.byteOffset()).arg(e.attribute("len")));
      94            0 :             return;
      95              :         }
      96           14 :         irregular = true;
      97              :     }
      98              : 
      99        17611 :     while (e.readNextStartElement()) {
     100        11105 :         const AsciiStringView tag(e.name());
     101              : 
     102        11105 :         if (tag == "voice") {
     103         6519 :             ctx.setTrack(nextTrack++);
     104         6519 :             ctx.setTick(measure->tick());
     105         6519 :             readVoice(measure, e, ctx, staffIdx, irregular);
     106         4586 :         } else if (tag == "Marker" || tag == "Jump") {
     107            6 :             EngravingItem* el = Factory::createItemByName(tag, measure);
     108            6 :             el->setTrack(ctx.track());
     109            6 :             TRead::readItem(el, e, ctx);
     110            6 :             if (el->systemFlag() && el->isTopSystemObject()) {
     111            6 :                 el->setTrack(0); // original system object always goes on top
     112              :             }
     113            6 :             measure->add(el);
     114         4580 :         } else if (tag == "stretch") {
     115            0 :             double val = e.readDouble();
     116            0 :             if (val < 0.0) {
     117            0 :                 val = 0;
     118              :             }
     119            0 :             measure->setUserStretch(val);
     120         4580 :         } else if (tag == "noOffset") {
     121            0 :             measure->setMeasureNumberOffset(e.readInt());
     122         4580 :         } else if (tag == "measureNumberMode") {
     123            0 :             measure->setMeasureNumberMode(MeasureNumberMode(e.readInt()));
     124         4580 :         } else if (tag == "irregular") {
     125            1 :             measure->setExcludeFromNumbering(e.readBool());
     126         4579 :         } else if (tag == "breakMultiMeasureRest") {
     127            0 :             measure->setBreakMultiMeasureRest(e.readBool());
     128         4579 :         } else if (tag == "startRepeat") {
     129            3 :             measure->setRepeatStart(true);
     130            3 :             e.readNext();
     131         4576 :         } else if (tag == "endRepeat") {
     132            9 :             measure->setRepeatCount(e.readInt());
     133            9 :             measure->setRepeatEnd(true);
     134         4567 :         } else if (tag == "vspacer" || tag == "vspacerDown") {
     135            0 :             if (!measure->mstaves()[staffIdx]->vspacerDown()) {
     136            0 :                 Spacer* spacer = Factory::createSpacer(measure);
     137            0 :                 spacer->setSpacerType(SpacerType::DOWN);
     138            0 :                 spacer->setTrack(staffIdx * VOICES);
     139            0 :                 measure->add(spacer);
     140              :             }
     141            0 :             measure->mstaves()[staffIdx]->vspacerDown()->setGap(Spatium(e.readDouble()));
     142         4567 :         } else if (tag == "vspacerFixed") {
     143            0 :             if (!measure->mstaves()[staffIdx]->vspacerDown()) {
     144            0 :                 Spacer* spacer = Factory::createSpacer(measure);
     145            0 :                 spacer->setSpacerType(SpacerType::FIXED);
     146            0 :                 spacer->setTrack(staffIdx * VOICES);
     147            0 :                 measure->add(spacer);
     148              :             }
     149            0 :             measure->mstaves()[staffIdx]->vspacerDown()->setGap(Spatium(e.readDouble()));
     150         4567 :         } else if (tag == "vspacerUp") {
     151            0 :             if (!measure->mstaves()[staffIdx]->vspacerUp()) {
     152            0 :                 Spacer* spacer = Factory::createSpacer(measure);
     153            0 :                 spacer->setSpacerType(SpacerType::UP);
     154            0 :                 spacer->setTrack(staffIdx * VOICES);
     155            0 :                 measure->add(spacer);
     156              :             }
     157            0 :             measure->mstaves()[staffIdx]->vspacerUp()->setGap(Spatium(e.readDouble()));
     158         4567 :         } else if (tag == "visible") {
     159            0 :             measure->mstaves()[staffIdx]->setVisible(e.readInt());
     160         4567 :         } else if (tag == "stemless") {
     161            2 :             measure->mstaves()[staffIdx]->setStemless(e.readInt());
     162         4565 :         } else if (tag == "hideIfEmpty") {
     163            0 :             measure->mstaves()[staffIdx]->setHideIfEmpty(TConv::fromXml(e.readAsciiText(), AutoOnOff::AUTO));
     164         4565 :         } else if (tag == "measureRepeatCount") {
     165          106 :             measure->setMeasureRepeatCount(e.readInt(), staffIdx);
     166         4459 :         } else if (tag == "SystemDivider") {
     167            0 :             SystemDivider* sd = new SystemDivider(ctx.dummy());
     168            0 :             TRead::read(sd, e, ctx);
     169              :             //! TODO Looks like a bug.
     170              :             //! The SystemDivider parent must be System
     171              :             //! there is a method: `System* system() const { return (System*)parent(); }`,
     172              :             //! but when we add it to Measure, the parent will be rewritten.
     173            0 :             measure->add(sd);
     174         4459 :         } else if (tag == "multiMeasureRest") {
     175           14 :             measure->setMMRestCount(e.readInt());
     176              :             // set tick to previous measure
     177           14 :             measure->setTick(ctx.lastMeasure()->tick());
     178           14 :             ctx.setTick(ctx.lastMeasure()->tick());
     179         4445 :         } else if (tag == "mmRestLast") {
     180           10 :             AsciiStringView s = e.readAsciiText();
     181           10 :             EID eid = EID::fromStdString(s);
     182           10 :             DO_ASSERT(eid.isValid());
     183           10 :             ctx.addMMRestEndMeasureEID(measure, eid);
     184         4435 :         } else if (tag == "MeasureNumber") {
     185            0 :             MeasureNumber* noText = new MeasureNumber(measure);
     186            0 :             TRead::read(noText, e, ctx);
     187            0 :             noText->setTrack(ctx.track());
     188            0 :             measure->add(noText);
     189         4435 :         } else if (tag == "MMRestRange") {
     190            0 :             MMRestRange* range = new MMRestRange(measure);
     191            0 :             TRead::read(range, e, ctx);
     192            0 :             range->setTrack(ctx.track());
     193            0 :             measure->add(range);
     194         4435 :         } else if (TRead::readProperties(static_cast<MeasureBase*>(measure), e, ctx)) {
     195              :         } else {
     196            0 :             e.unknown();
     197              :         }
     198              :     }
     199         6506 :     if (measure->isMMRest()) {
     200           14 :         Measure* lm = ctx.lastMeasure();
     201           14 :         ctx.setTick(lm->endTick());
     202              :     }
     203         6506 :     ctx.setCurrentMeasure(nullptr);
     204              : 
     205         6506 :     measure->connectTremolo();
     206              : }
     207              : 
     208         6519 : void MeasureRead::readVoice(Measure* measure, XmlReader& e, ReadContext& ctx, int staffIdx, bool irregular)
     209              : {
     210         6519 :     Segment* segment = nullptr;
     211         6519 :     std::vector<Chord*> graceNotes;
     212         6519 :     Beam* startingBeam = nullptr;
     213         6519 :     Tuplet* tuplet = nullptr;
     214         6519 :     Fermata* fermata = nullptr;
     215              : 
     216         6519 :     Staff* staff = ctx.staff(staffIdx);
     217         6519 :     Fraction timeStretch(staff->timeStretch(measure->tick()));
     218              : 
     219        17062 :     while (e.readNextStartElement()) {
     220        10543 :         const AsciiStringView tag(e.name());
     221              : 
     222        10543 :         if (tag == "location") {
     223            2 :             Location loc = Location::relative();
     224            2 :             TRead::read(&loc, e, ctx);
     225            2 :             ctx.setLocation(loc);
     226            2 :             if (loc.isTimeTick()) {
     227            0 :                 EditTimeTickAnchors::createTimeTickAnchor(measure, ctx.tick() - measure->tick(), track2staff(ctx.track()));
     228              :             }
     229        10541 :         } else if (tag == "tick") {             // obsolete?
     230            0 :             LOGD() << "read midi tick";
     231            0 :             ctx.setTick(Fraction::fromTicks(ctx.fileDivision(e.readInt())));
     232        10541 :         } else if (tag == "BarLine") {
     233           15 :             BarLine* barLine = Factory::createBarLine(ctx.dummy());
     234           15 :             barLine->setTrack(ctx.track());
     235           15 :             TRead::read(barLine, e, ctx);
     236              :             //
     237              :             //  StartRepeatBarLine: at rtick == 0, always BarLineType::START_REPEAT
     238              :             //  BarLine:            in the middle of a measure, has no semantic
     239              :             //  EndBarLine:         at the end of a measure
     240              :             //  BeginBarLine:       first segment of a measure, systemic barline
     241              : 
     242           15 :             SegmentType st = SegmentType::Invalid;
     243           15 :             Fraction t = ctx.tick() - measure->tick();
     244           15 :             if (t.isNotZero() && (t != measure->ticks())) {
     245            0 :                 st = SegmentType::BarLine;
     246           15 :             } else if (barLine->barLineType() == BarLineType::START_REPEAT && t.isZero()) {
     247            0 :                 st = SegmentType::StartRepeatBarLine;
     248           15 :             } else if (barLine->barLineType() == BarLineType::START_REPEAT && t == measure->ticks()) {
     249              :                 // old version, ignore
     250            0 :                 delete barLine;
     251            0 :                 barLine = 0;
     252           15 :             } else if (t.isZero() && segment == 0) {
     253            0 :                 st = SegmentType::BeginBarLine;
     254              :             } else {
     255           15 :                 st = SegmentType::EndBarLine;
     256              :             }
     257           15 :             if (barLine) {
     258           15 :                 segment = measure->getSegmentR(st, t);
     259           15 :                 segment->add(barLine);
     260              :             }
     261           15 :             if (fermata) {
     262            0 :                 segment->add(fermata);
     263            0 :                 fermata = nullptr;
     264              :             }
     265        10526 :         } else if (tag == "Chord") {
     266         2717 :             Chord* chord = Factory::createChord(ctx.dummy());
     267         2717 :             chord->setTrack(ctx.track());
     268         2717 :             TRead::read(chord, e, ctx);
     269         2717 :             if (startingBeam) {
     270          453 :                 startingBeam->add(chord);         // also calls chord->setBeam(startingBeam)
     271          453 :                 startingBeam = nullptr;
     272              :             }
     273              : //                  if (tuplet && !chord->isGrace())
     274              : //                        chord->readAddTuplet(tuplet);
     275         2717 :             segment = measure->getSegment(SegmentType::ChordRest, ctx.tick());
     276         2717 :             if (chord->noteType() != NoteType::NORMAL) {
     277            4 :                 graceNotes.push_back(chord);
     278              :             } else {
     279         2713 :                 segment->add(chord);
     280         2717 :                 for (size_t i = 0; i < graceNotes.size(); ++i) {
     281            4 :                     Chord* gc = graceNotes[i];
     282            4 :                     gc->setGraceIndex(static_cast<int>(i));
     283            4 :                     chord->add(gc);
     284              :                 }
     285         2713 :                 graceNotes.clear();
     286         2713 :                 if (tuplet) {
     287          299 :                     tuplet->add(chord);
     288              :                 }
     289         2713 :                 ctx.incTick(chord->actualTicks());
     290              :             }
     291         2717 :             if (fermata) {
     292            1 :                 segment->add(fermata);
     293            1 :                 fermata = nullptr;
     294              :             }
     295         7809 :         } else if (tag == "Rest") {
     296         6294 :             if (measure->isMMRest()) {
     297           14 :                 segment = measure->getSegment(SegmentType::ChordRest, ctx.tick());
     298           14 :                 MMRest* mmr = Factory::createMMRest(segment);
     299           14 :                 mmr->setTrack(ctx.track());
     300           14 :                 TRead::read(mmr, e, ctx);
     301           14 :                 segment->add(mmr);
     302           14 :                 ctx.incTick(mmr->actualTicks());
     303              :             } else {
     304         6280 :                 segment = measure->getSegment(SegmentType::ChordRest, ctx.tick());
     305         6280 :                 Rest* rest = Factory::createRest(segment);
     306         6280 :                 rest->setDurationType(DurationType::V_MEASURE);
     307         6280 :                 rest->setTicks(measure->timesig() / timeStretch);
     308         6280 :                 rest->setTrack(ctx.track());
     309         6280 :                 TRead::read(rest, e, ctx);
     310         6280 :                 if (startingBeam) {
     311            0 :                     startingBeam->add(rest); // also calls rest->setBeam(startingBeam)
     312            0 :                     startingBeam = nullptr;
     313              :                 }
     314              : 
     315         6280 :                 segment->add(rest);
     316         6280 :                 if (fermata) {
     317            0 :                     segment->add(fermata);
     318            0 :                     fermata = nullptr;
     319              :                 }
     320              : 
     321         6280 :                 if (!rest->ticks().isValid()) {    // hack
     322            0 :                     rest->setTicks(measure->timesig() / timeStretch);
     323              :                 }
     324              : 
     325         6280 :                 if (tuplet) {
     326          131 :                     tuplet->add(rest);
     327              :                 }
     328         6280 :                 ctx.incTick(rest->actualTicks());
     329              :             }
     330         1515 :         } else if (tag == "Breath") {
     331           10 :             segment = measure->getSegment(SegmentType::Breath, ctx.tick());
     332           10 :             Breath* breath = Factory::createBreath(segment);
     333           10 :             breath->setTrack(ctx.track());
     334           10 :             breath->setPlacement(breath->track() & 1 ? PlacementV::BELOW : PlacementV::ABOVE);
     335           10 :             TRead::read(breath, e, ctx);
     336           10 :             segment->add(breath);
     337         1505 :         } else if (tag == "MeasureRepeat" || tag == "RepeatMeasure") {
     338              :             //             4.x                       3.x
     339           50 :             segment = measure->getSegment(SegmentType::ChordRest, ctx.tick());
     340           50 :             MeasureRepeat* mr = Factory::createMeasureRepeat(segment);
     341           50 :             mr->setTrack(ctx.track());
     342           50 :             TRead::read(mr, e, ctx);
     343           50 :             if (!mr->numMeasures()) {
     344            0 :                 mr->setNumMeasures(1); // 3.x doesn't have any other possibilities
     345              :             }
     346           50 :             if (!measure->measureRepeatCount(staffIdx)) {
     347            0 :                 measure->setMeasureRepeatCount(1, staffIdx);
     348              :             }
     349           50 :             segment->add(mr);
     350           50 :             ctx.incTick(measure->ticks());
     351         1455 :         } else if (tag == "Clef") {
     352          170 :             Clef* clef = Factory::createClef(ctx.dummy());
     353          170 :             clef->setTrack(ctx.track());
     354          170 :             bool isHeader = false;
     355          170 :             TRead::read(clef, e, ctx, &isHeader);
     356          170 :             clef->setGenerated(false);
     357              : 
     358          170 :             segment = measure->getSegment(isHeader ? SegmentType::HeaderClef : SegmentType::Clef, ctx.tick());
     359          170 :             segment->add(clef);
     360         1285 :         } else if (tag == "TimeSig") {
     361          381 :             TimeSig* ts = Factory::createTimeSig(ctx.dummy());
     362          381 :             ts->setTrack(ctx.track());
     363          381 :             TRead::read(ts, e, ctx);
     364              : 
     365          381 :             Fraction currTick = ctx.tick();
     366          381 :             bool courtesySig = ts->isCourtesy();
     367          381 :             segment = measure->getSegment(courtesySig ? SegmentType::TimeSigAnnounce : SegmentType::TimeSig, currTick);
     368          381 :             segment->add(ts);
     369              : 
     370          381 :             if (!courtesySig) {
     371          381 :                 if (currTick == measure->endTick()) {
     372            0 :                     segment->setEndOfMeasureChange(true);
     373            0 :                     measure->setEndOfMeasureChange(true);
     374              :                 }
     375              : 
     376          381 :                 if (currTick == measure->tick()) {
     377          381 :                     timeStretch = ts->stretch().reduced();
     378          381 :                     measure->setTimesig(ts->sig() / timeStretch);
     379              : 
     380          381 :                     if (!irregular) {
     381          379 :                         measure->setTicks(measure->timesig());
     382              :                     }
     383              :                 }
     384              : 
     385          381 :                 if (currTick > measure->tick()) {
     386            0 :                     ctx.setTimeSigForNextMeasure(ts->sig() / ts->stretch().reduced());
     387              :                 }
     388              :             }
     389          904 :         } else if (tag == "KeySig") {
     390           74 :             KeySig* ks = Factory::createKeySig(ctx.dummy());
     391           74 :             ks->setTrack(ctx.track());
     392           74 :             TRead::read(ks, e, ctx);
     393              : 
     394           74 :             Fraction curTick = ctx.tick();
     395           74 :             bool courtesySig = ks->isCourtesy();
     396           74 :             segment = measure->getSegment(courtesySig ? SegmentType::KeySigAnnounce : SegmentType::KeySig, curTick);
     397           74 :             segment->add(ks);
     398              : 
     399           74 :             if (!courtesySig) {
     400           74 :                 if (curTick == measure->endTick()) {
     401            0 :                     segment->setEndOfMeasureChange(true);
     402            0 :                     measure->setEndOfMeasureChange(true);
     403              :                 }
     404              : 
     405           74 :                 staff->setKey(curTick, ks->keySigEvent());
     406              :             }
     407          830 :         } else if (tag == "Text") {
     408            0 :             segment = measure->getSegment(SegmentType::ChordRest, ctx.tick());
     409            0 :             StaffText* t = Factory::createStaffText(segment);
     410            0 :             t->setTrack(ctx.track());
     411            0 :             TRead::read(t, e, ctx);
     412            0 :             if (t->empty()) {
     413            0 :                 LOGD("==reading empty text: deleted");
     414            0 :                 delete t;
     415              :             } else {
     416            0 :                 segment->add(t);
     417              :             }
     418              :         }
     419              :         //----------------------------------------------------
     420              :         // Annotation
     421          830 :         else if (tag == "Dynamic") {
     422           95 :             segment = measure->getChordRestOrTimeTickSegment(ctx.tick());
     423           95 :             Dynamic* dyn = Factory::createDynamic(segment);
     424           95 :             dyn->setTrack(ctx.track());
     425           95 :             TRead::read(dyn, e, ctx);
     426           95 :             segment->add(dyn);
     427          735 :         } else if (tag == "Expression") {
     428            0 :             segment = measure->getChordRestOrTimeTickSegment(ctx.tick());
     429            0 :             Expression* expr = Factory::createExpression(segment);
     430            0 :             expr->setTrack(ctx.track());
     431            0 :             TRead::read(expr, e, ctx);
     432            0 :             segment->add(expr);
     433          735 :         } else if (tag == "Harmony") {
     434            3 :             segment = measure->getSegment(SegmentType::ChordRest, ctx.tick());
     435            3 :             Harmony* el = Factory::createHarmony(segment);
     436              : 
     437            3 :             el->setTrack(ctx.track());
     438            3 :             TRead::read(el, e, ctx);
     439            3 :             if (el->systemFlag() && el->isTopSystemObject()) {
     440            0 :                 el->setTrack(0); // original system object always goes on top
     441              :             }
     442            3 :             if (el->chords().empty()) {
     443              :                 // Invalid harmony
     444            0 :                 delete el;
     445              :             } else {
     446            3 :                 segment->add(el);
     447              :             }
     448          732 :         } else if (tag == "FretDiagram") {
     449            0 :             segment = measure->getSegment(SegmentType::ChordRest, ctx.tick());
     450            0 :             FretDiagram* el = Factory::createFretDiagram(segment);
     451              : 
     452            0 :             el->setTrack(ctx.track());
     453            0 :             TRead::read(el, e, ctx);
     454            0 :             if (el->systemFlag() && el->isTopSystemObject()) {
     455            0 :                 el->setTrack(0); // original system object always goes on top
     456              :             }
     457            0 :             segment->add(el);
     458          732 :         } else if (tag == "TremoloBar") {
     459            0 :             segment = measure->getSegment(SegmentType::ChordRest, ctx.tick());
     460            0 :             TremoloBar* el = Factory::createTremoloBar(segment);
     461            0 :             el->setTrack(ctx.track());
     462            0 :             TRead::read(el, e, ctx);
     463            0 :             if (el->systemFlag() && el->isTopSystemObject()) {
     464            0 :                 el->setTrack(0); // original system object always goes on top
     465              :             }
     466            0 :             segment->add(el);
     467          732 :         } else if (tag == "Symbol") {
     468            0 :             segment = measure->getSegment(SegmentType::ChordRest, ctx.tick());
     469            0 :             Symbol* el = Factory::createSymbol(segment);
     470              : 
     471            0 :             el->setTrack(ctx.track());
     472            0 :             TRead::read(el, e, ctx);
     473            0 :             if (el->systemFlag() && el->isTopSystemObject()) {
     474            0 :                 el->setTrack(0); // original system object always goes on top
     475              :             }
     476            0 :             segment->add(el);
     477          732 :         } else if (tag == "Tempo") {
     478          103 :             segment = measure->getChordRestOrTimeTickSegment(ctx.tick());
     479          103 :             TempoText* el = Factory::createTempoText(segment);
     480              : 
     481          103 :             el->setTrack(ctx.track());
     482          103 :             TRead::read(el, e, ctx);
     483          103 :             if (el->systemFlag() && el->isTopSystemObject()) {
     484          103 :                 el->setTrack(0); // original system object always goes on top
     485              :             }
     486          103 :             segment->add(el);
     487          629 :         } else if (tag == "StaffText") {
     488           15 :             segment = measure->getChordRestOrTimeTickSegment(ctx.tick());
     489           15 :             StaffText* el = Factory::createStaffText(segment);
     490           15 :             el->setTrack(ctx.track());
     491           15 :             TRead::read(el, e, ctx);
     492           15 :             if (el->systemFlag() && el->isTopSystemObject()) {
     493            0 :                 el->setTrack(0);     // original system object always goes on top
     494              :             }
     495           15 :             segment->add(el);
     496          614 :         } else if (tag == "Sticking"
     497          614 :                    || tag == "SystemText"
     498          613 :                    || tag == "PlayTechAnnotation"
     499          613 :                    || tag == "Capo"
     500          613 :                    || tag == "StringTunings"
     501          613 :                    || tag == "RehearsalMark"
     502          613 :                    || tag == "InstrumentChange"
     503          608 :                    || tag == "StaffState"
     504          608 :                    || tag == "FiguredBass"
     505         1228 :                    || tag == "HarpPedalDiagram"
     506              :                    ) {
     507           10 :             EngravingItem* el = Factory::createItemByName(tag, ctx.dummy());
     508           10 :             if (el->allowTimeAnchor()) {
     509            0 :                 segment = measure->getChordRestOrTimeTickSegment(ctx.tick());
     510              :             } else {
     511           10 :                 segment = measure->getSegment(SegmentType::ChordRest, ctx.tick());
     512              :             }
     513              : 
     514           10 :             el->setTrack(ctx.track());
     515           10 :             TRead::readItem(el, e, ctx);
     516           10 :             if (el->systemFlag() && el->isTopSystemObject()) {
     517            1 :                 el->setTrack(0); // original system object always goes on top
     518              :             }
     519           10 :             segment->add(el);
     520          604 :         } else if (tag == "Fermata") {
     521            1 :             fermata = Factory::createFermata(ctx.dummy());
     522            1 :             fermata->setTrack(ctx.track());
     523            1 :             fermata->setPlacement(fermata->track() & 1 ? PlacementV::BELOW : PlacementV::ABOVE);
     524            1 :             TRead::read(fermata, e, ctx);
     525          603 :         } else if (tag == "Image") {
     526            0 :             if (MScore::noImages) {
     527            0 :                 e.skipCurrentElement();
     528              :             } else {
     529            0 :                 segment = measure->getSegment(SegmentType::ChordRest, ctx.tick());
     530            0 :                 Image* el = Factory::createImage(segment);
     531            0 :                 el->setTrack(ctx.track());
     532            0 :                 TRead::read(el, e, ctx);
     533            0 :                 segment->add(el);
     534              :             }
     535          603 :         } else if (tag == "PlayCountText") {
     536            0 :             segment = measure->getSegment(SegmentType::EndBarLine, ctx.tick());
     537            0 :             EngravingItem* el = Factory::createItemByName(tag, segment);
     538              : 
     539            0 :             el->setTrack(ctx.track());
     540            0 :             TRead::readItem(el, e, ctx);
     541            0 :             if (el->systemFlag() && el->isTopSystemObject()) {
     542            0 :                 el->setTrack(0); // original system object always goes on top
     543              :             }
     544            0 :             segment->add(el);
     545              :         }
     546              :         //----------------------------------------------------
     547          603 :         else if (tag == "Tuplet") {
     548           75 :             Tuplet* oldTuplet = tuplet;
     549           75 :             tuplet = Factory::createTuplet(measure);
     550           75 :             tuplet->setTrack(ctx.track());
     551           75 :             tuplet->setTick(ctx.tick());
     552           75 :             TRead::read(tuplet, e, ctx);
     553           75 :             if (oldTuplet) {
     554           13 :                 oldTuplet->add(tuplet);
     555              :             }
     556          528 :         } else if (tag == "endTuplet") {
     557           75 :             if (!tuplet) {
     558            0 :                 LOGD("Measure::read: encountered <endTuplet/> when no tuplet was started");
     559            0 :                 e.skipCurrentElement();
     560            0 :                 continue;
     561              :             }
     562           75 :             Tuplet* oldTuplet = tuplet;
     563           75 :             tuplet = tuplet->tuplet();
     564           75 :             if (oldTuplet->elements().empty()) {
     565              :                 // this should not happen and is a sign of input file corruption
     566            0 :                 LOGD("Measure:read: empty tuplet in measure index=%d, input file corrupted?", ctx.currentMeasureIndex());
     567            0 :                 if (tuplet) {
     568            0 :                     tuplet->remove(oldTuplet);
     569              :                 }
     570            0 :                 delete oldTuplet;
     571              :             }
     572           75 :             e.readNext();
     573          453 :         } else if (tag == "Beam") {
     574          453 :             Beam* beam = Factory::createBeam(ctx.score());
     575          453 :             beam->setTrack(ctx.track());
     576          453 :             TRead::read(beam, e, ctx);
     577          453 :             if (startingBeam) {
     578            0 :                 LOGD("The read beam was not used");
     579            0 :                 delete startingBeam;
     580              :             }
     581          453 :             startingBeam = beam;
     582            0 :         } else if (tag == "Segment" && segment) {
     583            0 :             TRead::read(segment, e, ctx);
     584            0 :         } else if (tag == "Ambitus") {
     585            0 :             segment = measure->getSegment(SegmentType::Ambitus, ctx.tick());
     586            0 :             Ambitus* range = Factory::createAmbitus(segment);
     587            0 :             TRead::read(range, e, ctx);
     588            0 :             range->setTrack(trackZeroVoice(ctx.track()));
     589            0 :             segment->add(range);
     590              :         } else {
     591            0 :             e.unknown();
     592              :         }
     593              :     }
     594         6519 :     if (startingBeam) {
     595            0 :         LOGD("The read beam was not used");
     596            0 :         delete startingBeam;
     597              :     }
     598         6519 :     if (tuplet) {
     599            0 :         LOGD("Measure:readVoice: measure index=%d, <endTuplet/> not found", ctx.currentMeasureIndex());
     600            0 :         if (tuplet->elements().empty()) {
     601            0 :             if (tuplet->tuplet()) {
     602            0 :                 tuplet->tuplet()->remove(tuplet);
     603              :             }
     604            0 :             delete tuplet;
     605              :         }
     606              :     }
     607         6519 :     if (fermata) {
     608            0 :         SegmentType st = (ctx.tick() == measure->endTick() ? SegmentType::EndBarLine : SegmentType::ChordRest);
     609            0 :         segment = measure->getSegment(st, ctx.tick());
     610            0 :         segment->add(fermata);
     611            0 :         fermata = nullptr;
     612              :     }
     613         6519 : }
        

Generated by: LCOV version 2.0-1