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

Generated by: LCOV version 2.0-1