LCOV - code coverage report
Current view: top level - src/engraving/dom - range.cpp Coverage Total Hit
Test: filtered_coverage.info Lines: 68.6 % 848 582
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 "range.h"
      24              : 
      25              : #include "barline.h"
      26              : #include "chord.h"
      27              : #include "excerpt.h"
      28              : #include "factory.h"
      29              : #include "linkedobjects.h"
      30              : #include "measure.h"
      31              : #include "measurerepeat.h"
      32              : #include "note.h"
      33              : #include "rest.h"
      34              : #include "score.h"
      35              : #include "segment.h"
      36              : #include "slur.h"
      37              : #include "staff.h"
      38              : #include "tie.h"
      39              : #include "spacer.h"
      40              : #include "marker.h"
      41              : #include "volta.h"
      42              : 
      43              : #include "tremolosinglechord.h"
      44              : #include "tremolotwochord.h"
      45              : #include "tuplet.h"
      46              : #include "utils.h"
      47              : 
      48              : #include "log.h"
      49              : 
      50              : using namespace mu;
      51              : using namespace mu::engraving;
      52              : 
      53              : namespace mu::engraving {
      54              : //---------------------------------------------------------
      55              : //   cleanupTuplet
      56              : //---------------------------------------------------------
      57              : 
      58           12 : static void cleanupTuplet(Tuplet* t)
      59              : {
      60           12 :     const auto elements(t->elements());
      61           12 :     t->clear();
      62           48 :     for (DurationElement* e : elements) {
      63           36 :         e->setTuplet(nullptr);     // prevent deleting the top tuplet by its children
      64           36 :         if (e->isTuplet()) {
      65            6 :             cleanupTuplet(toTuplet(e));
      66              :         }
      67           36 :         delete e;
      68              :     }
      69           12 : }
      70              : 
      71              : //   clonedNote
      72              : //---------------------------------------------------------
      73          494 : static Note* clonedNote(const Note* srcNote, TrackList::ClonedChordMap& cChordMap)
      74              : {
      75          494 :     Note* cNote = nullptr;
      76          494 :     Chord* srcChord = srcNote->chord();
      77          494 :     Chord* cChord = cChordMap[srcChord];
      78              : 
      79          494 :     if (srcChord && cChord) {
      80          494 :         int noteSrcPosition = 0;
      81          494 :         int noteClonedPosition = 0;
      82          494 :         bool noteFound = false;
      83              :         // We presume notes where created in the same order in the srcChord and clonedChord
      84              :         // Note position in sourceChord
      85          504 :         for (Note* n : srcChord->notes()) {
      86          504 :             ++noteSrcPosition;
      87          504 :             if (srcNote == n) {
      88          494 :                 noteFound = true;
      89          494 :                 break;
      90              :             }
      91              :         }
      92          494 :         if (noteFound) {
      93              :             // Note in clonedChord
      94          504 :             for (Note* n : cChord->notes()) {
      95          504 :                 ++noteClonedPosition;
      96          504 :                 if (noteClonedPosition == noteSrcPosition) {
      97          494 :                     cNote = n;
      98          494 :                     break;
      99              :                 }
     100              :             }
     101              :         }
     102              :     }
     103          494 :     return cNote;
     104              : }
     105              : 
     106              : //---------------------------------------------------------
     107              : //   cloneAndRebuildSpanners
     108              : //---------------------------------------------------------
     109          298 : static void cloneAndRebuildSpanners(TrackList::ClonedChordMap& cChordMap)
     110              : {
     111          298 :     Chord* srcChord = nullptr;
     112          298 :     Note* cNote = nullptr;
     113          298 :     auto iter = cChordMap.begin();
     114              : 
     115              :     // Clone Spanners from Chords
     116          784 :     while (iter != cChordMap.end()) {
     117          486 :         srcChord = iter->first;
     118              : 
     119              :         //
     120              :         // Add For and Back Note's spanners to cloned Note
     121              :         //
     122          980 :         for (Note* srcNote : srcChord->notes()) {
     123          494 :             cNote = clonedNote(srcNote, cChordMap);
     124              : 
     125          494 :             if (cNote) {
     126          494 :                 for (Spanner* sp : srcNote->spannerFor()) {
     127            0 :                     if (sp->isGuitarBend() || sp->isGlissando()) {
     128            0 :                         Spanner* csp = toSpanner(sp->clone());
     129              : 
     130            0 :                         Note* endClonedNote = clonedNote(toNote(sp->endElement()), cChordMap);
     131            0 :                         if (endClonedNote) {
     132            0 :                             csp->setNoteSpan(cNote, endClonedNote);
     133              :                         }
     134            0 :                         cNote->addSpannerFor(csp);
     135              :                     }
     136              :                 }
     137          494 :                 for (Spanner* sp : srcNote->spannerBack()) {
     138            0 :                     if (sp->isGuitarBend() || sp->isGlissando()) {
     139            0 :                         Spanner* csp = toSpanner(sp->clone());
     140            0 :                         Note* startClonedNote = clonedNote(toNote(sp->startElement()), cChordMap);
     141              : 
     142            0 :                         if (startClonedNote) {
     143            0 :                             csp->setNoteSpan(startClonedNote, cNote);
     144              :                         }
     145            0 :                         cNote->addSpannerBack(csp);
     146              :                     }
     147              :                 }
     148              :             }
     149              :         }
     150          486 :         ++iter;
     151              :     }
     152          298 : }
     153              : 
     154              : //---------------------------------------------------------
     155              : //   TrackList
     156              : //---------------------------------------------------------
     157              : 
     158          236 : TrackList::~TrackList()
     159              : {
     160          236 :     m_clonedChord.clear();
     161          770 :     for (EngravingItem* e : *this) {
     162          534 :         if (e->isTuplet()) {
     163            6 :             Tuplet* t = toTuplet(e);
     164            6 :             cleanupTuplet(t);
     165              :         } else {
     166          528 :             delete e;
     167              :         }
     168              :     }
     169          236 : }
     170              : 
     171              : //---------------------------------------------------------
     172              : //   appendTuplet
     173              : //---------------------------------------------------------
     174              : 
     175           12 : void TrackList::appendTuplet(Tuplet* srcTuplet, Tuplet* dstTuplet)
     176              : {
     177           48 :     for (DurationElement* de : srcTuplet->elements()) {
     178           36 :         DurationElement* e = toDurationElement(de->clone());
     179           36 :         dstTuplet->add(e);
     180           36 :         if (de->isTuplet()) {
     181            6 :             Tuplet* st = toTuplet(de);
     182            6 :             Tuplet* dt = toTuplet(e);
     183            6 :             appendTuplet(st, dt);
     184           30 :         } else if (de->ownershipParent() && de->ownershipParent()->isSegment()) {
     185           30 :             Segment* seg = toSegment(de->ownershipParent());
     186           30 :             for (EngravingItem* ee : seg->annotations()) {
     187            0 :                 bool addSysObject = ee->systemFlag() && !ee->isLinked() && ee->track() == 0 && e->track() == 0;
     188            0 :                 if (addSysObject || (!ee->systemFlag() && ee->track() == e->track())) {
     189            0 :                     m_range->m_annotations.push_back({ e->tick(), ee->clone() });
     190              :                 }
     191              :             }
     192              :         }
     193              :     }
     194           12 : }
     195              : 
     196              : //---------------------------------------------------------
     197              : //   combineTuplet
     198              : //---------------------------------------------------------
     199              : 
     200            0 : void TrackList::combineTuplet(Tuplet* dst, Tuplet* src)
     201              : {
     202            0 :     dst->setTicks(dst->ticks() * 2);
     203            0 :     dst->setBaseLen(dst->baseLen().shift(-1));
     204              : 
     205              :     // try to combine tie'd notes
     206            0 :     unsigned idx = 0;
     207            0 :     if (dst->elements().back()->isChord() && src->elements().front()->isChord()) {
     208            0 :         Chord* chord = toChord(src->elements().front());
     209            0 :         bool akkumulateChord = true;
     210            0 :         for (Note* n : chord->notes()) {
     211            0 :             if (!n->tieBackNonPartial() || !n->tieBack()->generated()) {
     212            0 :                 akkumulateChord = false;
     213            0 :                 break;
     214              :             }
     215              :         }
     216            0 :         if (akkumulateChord) {
     217            0 :             Chord* bc  = toChord(dst->elements().back());
     218            0 :             bc->setTicks(bc->ticks() + chord->ticks());
     219              : 
     220              :             // forward ties
     221            0 :             int i = 0;
     222            0 :             for (Note* n : bc->notes()) {
     223            0 :                 n->setTieFor(chord->notes()[i]->tieFor());
     224            0 :                 ++i;
     225              :             }
     226            0 :             idx = 1;          // skip first src element
     227              :         }
     228              :     }
     229              : 
     230            0 :     for (; idx < src->elements().size(); ++idx) {
     231            0 :         DurationElement* de = src->elements()[idx];
     232            0 :         DurationElement* e = toDurationElement(de->clone());
     233            0 :         dst->add(e);
     234            0 :         if (de->isTuplet()) {
     235            0 :             Tuplet* st = toTuplet(de);
     236            0 :             Tuplet* dt = toTuplet(e);
     237            0 :             appendTuplet(st, dt);
     238              :         }
     239              :     }
     240            0 : }
     241              : 
     242              : //---------------------------------------------------------
     243              : //   append
     244              : //---------------------------------------------------------
     245              : 
     246          382 : void TrackList::append(EngravingItem* e)
     247              : {
     248          382 :     if (e->isDurationElement()) {
     249          318 :         m_duration += toDurationElement(e)->ticks();
     250              : 
     251          318 :         bool accumulateRest = e->isRest() && !empty() && back()->isRest();
     252          318 :         Segment* s          = accumulateRest ? toRest(e)->segment() : 0;
     253              : 
     254          318 :         if (s && !s->score()->isSpannerStartEnd(s->tick(), e->track()) && !s->annotations().size()) {
     255              :             // akkumulate rests
     256           23 :             Rest* rest  = toRest(back());
     257           23 :             Fraction du = rest->ticks();
     258           23 :             du += toRest(e)->ticks();
     259           23 :             rest->setTicks(du);
     260              :         } else {
     261          295 :             EngravingItem* element = 0;
     262          295 :             if (e->isTuplet()) {
     263            6 :                 Tuplet* src = toTuplet(e);
     264            6 :                 if (src->generated() && !empty() && back()->isTuplet()) {
     265            0 :                     Tuplet* b = toTuplet(back());
     266            0 :                     combineTuplet(b, src);
     267              :                 } else {
     268            6 :                     element = e->clone();
     269            6 :                     Tuplet* dst = toTuplet(element);
     270            6 :                     appendTuplet(src, dst);
     271              :                 }
     272              :             } else {
     273          289 :                 element = e->clone();
     274          289 :                 ChordRest* src = toChordRest(e);
     275          289 :                 Segment* s1 = src->segment();
     276          302 :                 for (EngravingItem* ee : s1->annotations()) {
     277           13 :                     bool addSysObject = ee->systemFlag() && !ee->isLinked() && ee->track() == 0 && e->track() == 0;
     278           13 :                     if (addSysObject || (!ee->systemFlag() && ee->track() == e->track())) {
     279           13 :                         m_range->m_annotations.push_back({ s1->tick(), ee->clone() });
     280              :                     }
     281              :                 }
     282          289 :                 if (e->isChord()) {
     283          243 :                     Chord* chord = toChord(e);
     284              : 
     285              :                     // Map between Chords and clonned chords
     286          243 :                     m_clonedChord.insert(std::make_pair(chord, toChord(element)));
     287              : 
     288          243 :                     bool akkumulateChord = true;
     289          243 :                     for (Note* n : chord->notes()) {
     290          243 :                         if (!n->tieBackNonPartial() || !n->tieBack()->generated()) {
     291          243 :                             akkumulateChord = false;
     292          243 :                             break;
     293              :                         }
     294              :                     }
     295          243 :                     if (akkumulateChord && !empty() && back()->isChord()) {
     296            0 :                         Chord* bc   = toChord(back());
     297            0 :                         const Fraction du = bc->ticks() + chord->ticks();
     298            0 :                         bc->setTicks(du);
     299              : 
     300              :                         // forward ties
     301            0 :                         int idx = 0;
     302            0 :                         for (Note* n : bc->notes()) {
     303            0 :                             n->setTieFor(chord->notes()[idx]->tieFor());
     304            0 :                             ++idx;
     305              :                         }
     306            0 :                         delete element;
     307            0 :                         element = nullptr;
     308            0 :                         m_clonedChord.erase(chord);
     309              :                     }
     310              :                 }
     311              :             }
     312          295 :             if (element) {
     313          295 :                 element->setSelected(false);
     314          295 :                 std::vector<EngravingItem*>::push_back(element);
     315              :             }
     316              :         }
     317              :     } else {
     318           64 :         EngravingItem* c = e->clone();
     319           64 :         c->moveToDummy();   // the clone is unattached until it is written back into a segment
     320           64 :         std::vector<EngravingItem*>::push_back(c);
     321              :     }
     322          382 : }
     323              : 
     324              : //---------------------------------------------------------
     325              : //   appendGap
     326              : //---------------------------------------------------------
     327              : 
     328          265 : void TrackList::appendGap(const Fraction& du, Score* score)
     329              : {
     330          265 :     if (du.isZero()) {
     331           40 :         return;
     332              :     }
     333          225 :     EngravingItem* e = empty() ? 0 : back();
     334          225 :     if (e && e->isRest()) {
     335           50 :         Rest* rest  = toRest(back());
     336           50 :         Fraction dd = rest->ticks();
     337           50 :         dd          += du;
     338           50 :         m_duration   += du;
     339           50 :         rest->setTicks(dd);
     340              :     } else {
     341          175 :         Rest* rest = Factory::createRest(score->dummy());
     342          175 :         rest->setTicks(du);
     343          175 :         std::vector<EngravingItem*>::push_back(rest);
     344          175 :         m_duration   += du;
     345              :     }
     346              : }
     347              : 
     348              : //---------------------------------------------------------
     349              : //   truncate
     350              : //    reduce len of last gap by f
     351              : //---------------------------------------------------------
     352              : 
     353            0 : bool TrackList::truncate(const Fraction& f)
     354              : {
     355            0 :     if (empty()) {
     356            0 :         return true;
     357              :     }
     358            0 :     EngravingItem* e = back();
     359            0 :     if (!e->isRest()) {
     360            0 :         return false;
     361              :     }
     362            0 :     Rest* r = toRest(e);
     363            0 :     if (r->ticks() < f) {
     364            0 :         return false;
     365              :     }
     366            0 :     if (r->ticks() == f) {
     367            0 :         this->pop_back();
     368            0 :         delete r;
     369              :     } else {
     370            0 :         r->setTicks(r->ticks() - f);
     371              :     }
     372            0 :     m_duration -= f;
     373            0 :     return true;
     374              : }
     375              : 
     376              : //---------------------------------------------------------
     377              : //   read
     378              : //---------------------------------------------------------
     379              : 
     380          236 : void TrackList::read(const Segment* fs, const Segment* es)
     381              : {
     382          236 :     Fraction tick = fs->tick();
     383          236 :     m_clonedChord.clear();
     384              : 
     385              :     const Segment* s;
     386         2547 :     for (s = fs; s && (s != es); s = s->next1()) {
     387         2311 :         if (!s->enabled()) {
     388           16 :             continue;
     389              :         }
     390         2295 :         EngravingItem* e = s->element(m_track);
     391         2295 :         if (!e || e->generated()) {
     392         1956 :             for (EngravingItem* ee : s->annotations()) {
     393           43 :                 if (ee->systemFlag() && ee->track() != 0) {
     394              :                     // Only process the top system object
     395            0 :                     continue;
     396              :                 }
     397           43 :                 if (ee->track() == m_track) {
     398            1 :                     m_range->m_annotations.push_back({ s->tick(), ee->clone() });
     399              :                 }
     400              :             }
     401         1913 :             continue;
     402         1913 :         }
     403          382 :         if (e->isMeasureRepeat()) {
     404              :             // TODO: copy previous measure contents?
     405            1 :             MeasureRepeat* rm = toMeasureRepeat(e);
     406            1 :             Rest* r = Factory::copyRest(*rm);
     407              :             //! TODO Perhaps there is a bug.
     408              :             //! Previously, the element changed its type (because there was a virtual method that returned the type).
     409              :             //! This code has been added for compatibility reasons to maintain the same behavior.
     410            1 :             r->hack_toRestType();
     411            1 :             r->reset();
     412            1 :             append(r);
     413            1 :             tick += r->ticks();
     414          381 :         } else if (e->isChordRest()) {
     415          317 :             DurationElement* de = toDurationElement(e);
     416          317 :             Fraction gap = s->tick() - tick;
     417          317 :             if (de->tuplet()) {
     418            6 :                 Tuplet* t = de->topTuplet();
     419            6 :                 s  = skipTuplet(t);            // continue with first chord/rest after tuplet
     420            6 :                 de = t;
     421              :             }
     422              : 
     423          317 :             if (gap.isNotZero()) {
     424            0 :                 appendGap(gap, e->score());
     425            0 :                 tick += gap;
     426              :             }
     427          317 :             append(de);
     428          317 :             tick += de->ticks();
     429           64 :         } else if (e->isBarLine()) {
     430            0 :             BarLine* bl = toBarLine(e);
     431            0 :             if (bl->barLineType() != BarLineType::NORMAL) {
     432            0 :                 append(e);
     433              :             }
     434              :         } else {
     435           64 :             append(e);
     436              :         }
     437              :     }
     438          236 :     Fraction gap = es->tick() - tick;
     439          236 :     if (gap.isNotZero()) {
     440          169 :         appendGap(gap, es->score());
     441              :     }
     442              : 
     443              :     // Clone and rebuild Spanners
     444          236 :     cloneAndRebuildSpanners(m_clonedChord);
     445              : 
     446              :     //
     447              :     // connect ties
     448              :     //
     449          236 :     size_t n = size();
     450          764 :     for (size_t i = 0; i < n; ++i) {
     451          528 :         EngravingItem* e = at(i);
     452          528 :         if (!e->isChord()) {
     453          285 :             continue;
     454              :         }
     455          243 :         Chord* chord = toChord(e);
     456          490 :         for (Note* n1 : chord->notes()) {
     457          247 :             Tie* tie = n1->tieForNonPartial();
     458          247 :             if (!tie) {
     459          234 :                 continue;
     460              :             }
     461           13 :             for (size_t k = i + 1; k < n; ++k) {
     462            7 :                 EngravingItem* ee = at(k);
     463            7 :                 if (!ee->isChord()) {
     464            0 :                     continue;
     465              :                 }
     466            7 :                 Chord* c2 = toChord(ee);
     467            7 :                 bool found = false;
     468            7 :                 for (Note* n2 : c2->notes()) {
     469            7 :                     if (n1->pitch() == n2->pitch()) {
     470            7 :                         tie->setEndNote(n2);
     471            7 :                         n2->setTieBack(tie);
     472            7 :                         found = true;
     473            7 :                         break;
     474              :                     }
     475              :                 }
     476            7 :                 if (!found) {
     477            0 :                     LOGD("Tied note not found");
     478              :                 }
     479            7 :                 break;
     480              :             }
     481              :         }
     482              :     }
     483          236 :     m_clonedChord.clear();
     484          236 : }
     485              : 
     486              : //---------------------------------------------------------
     487              : //   checkRest
     488              : //---------------------------------------------------------
     489              : 
     490          349 : static bool checkRest(Fraction& rest, Measure*& m, const Fraction& d)
     491              : {
     492          349 :     if (rest.isZero()) {
     493           94 :         if (m->nextMeasure()) {
     494           94 :             m  = m->nextMeasure();
     495           94 :             rest = m->ticks();
     496              :         } else {
     497            0 :             LOGW("premature end of measure list, rest %d/%d", d.numerator(), d.denominator());
     498            0 :             return false;
     499              :         }
     500              :     }
     501          349 :     return true;
     502              : }
     503              : 
     504              : //---------------------------------------------------------
     505              : //   writeTuplet
     506              : //    measure - current measure
     507              : //    rest    - available time in measure
     508              : //---------------------------------------------------------
     509              : 
     510           11 : Tuplet* TrackList::writeTuplet(Tuplet* parent, Tuplet* tuplet, Measure*& measure, Fraction& rest) const
     511              : {
     512           11 :     Score* score = measure->score();
     513           11 :     Tuplet* dt   = tuplet->clone();
     514           11 :     dt->setOwnershipParent(measure);
     515           11 :     Fraction du  = tuplet->ticks();
     516           11 :     if (du > rest) {
     517              :         // we must split the tuplet
     518            7 :         dt->setTicks(du * Fraction(1, 2));
     519            7 :         dt->setBaseLen(tuplet->baseLen().shift(1));
     520              :     }
     521           11 :     if (parent) {
     522            6 :         parent->add(dt);
     523              :     }
     524              : 
     525           44 :     for (DurationElement* e : tuplet->elements()) {
     526           33 :         Fraction duration = e->globalTicks();
     527           33 :         Tuplet* tt        = dt;
     528           33 :         Fraction ratio    = Fraction(1, 1);
     529           87 :         while (tt) {
     530           54 :             ratio *= tt->ratio();
     531           54 :             tt = tt->tuplet();
     532              :         }
     533              : 
     534           33 :         bool firstpart = true;
     535           70 :         while (duration > Fraction(0, 1)) {
     536           37 :             if (rest.isZero()) {
     537            4 :                 if (measure->nextMeasure()) {
     538            4 :                     measure = measure->nextMeasure();
     539            4 :                     rest    = measure->ticks();
     540            4 :                     if (e != tuplet->elements().back()) {
     541              :                         // create second part of split tuplet
     542            4 :                         dt = dt->clone();
     543            4 :                         dt->setGenerated(true);
     544            4 :                         dt->setOwnershipParent(measure);
     545            4 :                         Tuplet* pt = dt;
     546            7 :                         while (parent) {
     547            3 :                             Tuplet* tt1 = parent->clone();
     548            3 :                             tt1->setGenerated(true);
     549            3 :                             tt1->setOwnershipParent(measure);
     550            3 :                             tt1->add(pt);
     551            3 :                             pt = tt1;
     552            3 :                             parent = parent->tuplet();
     553              :                         }
     554              :                     }
     555              :                 } else {
     556            0 :                     ASSERT_X(String(u"premature end of measure list in track %1, rest %2/%3")
     557              :                              .arg(m_track).arg(duration.numerator(), duration.denominator()));
     558              :                 }
     559              :             }
     560           37 :             if (e->isChordRest()) {
     561           31 :                 Fraction dd = std::min(rest, duration) * ratio;
     562           31 :                 std::vector<TDuration> dl = toDurationList(dd, false);
     563           62 :                 for (const TDuration& k : dl) {
     564           31 :                     Segment* segment = measure->undoGetSegmentR(SegmentType::ChordRest, measure->ticks() - rest);
     565           31 :                     Fraction gd      = k.fraction() / ratio;
     566           31 :                     ChordRest* cr    = toChordRest(e->clone());
     567           31 :                     if (!firstpart) {
     568            4 :                         cr->removeMarkings(true);
     569              :                     }
     570           31 :                     cr->setScore(score);
     571           31 :                     cr->setTrack(m_track);
     572           31 :                     segment->add(cr);
     573           31 :                     cr->setTicks(k.fraction());
     574           31 :                     cr->setDurationType(k);
     575           31 :                     rest     -= gd;
     576           31 :                     duration -= gd;
     577              : 
     578           31 :                     if (cr->isChord()) {
     579           54 :                         for (Note* note : toChord(cr)->notes()) {
     580           27 :                             if (!duration.isZero() && !note->tieFor()) {
     581            4 :                                 Tie* tie = Factory::createTie(note);
     582            4 :                                 tie->setGenerated(true);
     583            4 :                                 note->add(tie);
     584              :                             }
     585              :                         }
     586              :                     }
     587           31 :                     dt->add(cr);
     588           31 :                     firstpart = false;
     589              :                 }
     590           37 :             } else if (e->isTuplet()) {
     591            6 :                 Tuplet* tt1 = toTuplet(e);
     592            6 :                 Tuplet* ttt = writeTuplet(dt, tt1, measure, rest);
     593            6 :                 dt          = ttt->tuplet();
     594            6 :                 parent      = dt->tuplet();
     595            6 :                 duration    = Fraction();
     596              :             }
     597           37 :             firstpart = false;
     598              :         }
     599              :     }
     600           11 :     return dt;
     601              : }
     602              : 
     603              : //---------------------------------------------------------
     604              : //   write
     605              : //    rewrite notes into measure list measure
     606              : //---------------------------------------------------------
     607              : 
     608          229 : bool TrackList::write(Score* score, const Fraction& tick) const
     609              : {
     610          229 :     if ((m_track % VOICES) && size() == 1 && at(0)->isRest()) {     // don’t write rests in voice > 0
     611          166 :         return true;
     612              :     }
     613           63 :     ClonedChordMap wClonedChord;
     614           63 :     Measure* measure = score->tick2measure(tick);
     615           63 :     Measure* m       = measure;
     616           63 :     Fraction remains = m->endTick() - tick;
     617           63 :     Segment* segment = 0;
     618              : 
     619          420 :     for (EngravingItem* e : *this) {
     620          358 :         if (e->isDurationElement()) {
     621          296 :             Fraction duration = toDurationElement(e)->ticks();
     622          296 :             if (!checkRest(remains, m, duration)) {     // go to next measure, if necessary
     623            0 :                 MScore::setError(MsError::CORRUPTED_MEASURE);
     624            1 :                 return false;
     625              :             }
     626          296 :             if (duration > remains && e->isTuplet()) {
     627              :                 // experimental: allow tuplet split in the middle
     628            5 :                 if (duration != remains * 2) {
     629            1 :                     MScore::setError(MsError::CANNOT_SPLIT_TUPLET);
     630            1 :                     return false;
     631              :                 }
     632              :             }
     633          295 :             bool firstpart = true;
     634          643 :             while (duration > Fraction(0, 1)) {
     635          348 :                 if ((e->isRest() || e->isMeasureRepeat()) && (duration >= remains || e == back()) && (remains == m->ticks())) {
     636              :                     //
     637              :                     // handle full measure rest
     638              :                     //
     639           54 :                     Segment* seg = m->getSegmentR(SegmentType::ChordRest, m->ticks() - remains);
     640           54 :                     if ((m_track % VOICES) == 0) {
     641              :                         // write only for voice 1
     642           54 :                         Rest* r = Factory::createRest(seg, DurationType::V_MEASURE);
     643              :                         // ideally we should be using stretchedLen
     644              :                         // but this is not valid during rewrite when adding time signatures
     645              :                         // since the time signature has not been added yet
     646              :                         //Fraction stretchedLen = m->stretchedLen(staff);
     647              :                         //r->setTicks(stretchedLen);
     648           54 :                         r->setTicks(m->ticks());
     649           54 :                         r->setTrack(m_track);
     650           54 :                         seg->add(r);
     651              :                     }
     652           54 :                     duration -= m->ticks();
     653           54 :                     remains.set(0, 1);
     654          294 :                 } else if (e->isChordRest()) {
     655          289 :                     Fraction du               = std::min(remains, duration);
     656          289 :                     std::vector<TDuration> dl = toDurationList(du, e->isChord());
     657          289 :                     if (dl.empty()) {
     658            0 :                         MScore::setError(MsError::CORRUPTED_MEASURE);
     659            0 :                         return false;
     660              :                     }
     661          589 :                     for (const TDuration& k : dl) {
     662          300 :                         segment       = m->undoGetSegmentR(SegmentType::ChordRest, m->ticks() - remains);
     663          300 :                         ChordRest* cr = toChordRest(e->clone());
     664          300 :                         if (!firstpart) {
     665           20 :                             cr->removeMarkings(true);
     666              :                         }
     667          300 :                         cr->setTrack(m_track);
     668          300 :                         cr->setScore(score);
     669          300 :                         Fraction gd = k.fraction();
     670          300 :                         cr->setTicks(gd);
     671          300 :                         cr->setDurationType(k);
     672              : 
     673          300 :                         segment->add(cr);
     674          300 :                         duration -= gd;
     675          300 :                         remains  -= gd;
     676              : 
     677          300 :                         if (cr->isChord()) {
     678              :                             // Map between Chords and clonned chords
     679          255 :                             wClonedChord.insert(std::make_pair(toChord(e), toChord(cr)));
     680              : 
     681          255 :                             TremoloTwoChord* tremolo = toChord(cr)->tremoloTwoChord();
     682          255 :                             if (!firstpart && tremolo) {               // remove partial two-note tremolo
     683            0 :                                 if (toChord(e)->tremoloTwoChord()->chord1() == toChord(e)) {
     684            0 :                                     tremolo->setChords(toChord(cr), nullptr);
     685              :                                 } else {
     686            0 :                                     tremolo->setChords(nullptr, toChord(cr));
     687              :                                 }
     688            0 :                                 toChord(cr)->setTremoloTwoChord(nullptr);
     689            0 :                                 delete tremolo;
     690              :                             }
     691          516 :                             for (Note* note : toChord(cr)->notes()) {
     692          261 :                                 if (!duration.isZero() && !note->tieFor()) {
     693            9 :                                     Tie* tie = Factory::createTie(note);
     694            9 :                                     tie->setGenerated(true);
     695            9 :                                     note->add(tie);
     696              :                                 }
     697              :                             }
     698              :                         }
     699              :                     }
     700          294 :                 } else if (e->isTuplet()) {
     701            5 :                     writeTuplet(0, toTuplet(e), m, remains);
     702            5 :                     duration = Fraction();
     703              :                 }
     704          348 :                 firstpart = false;
     705          348 :                 if (duration > Fraction(0, 1)) {
     706           53 :                     if (!checkRest(remains, m, duration)) {     // go to next measure, if necessary
     707            0 :                         MScore::setError(MsError::CORRUPTED_MEASURE);
     708            0 :                         return false;
     709              :                     }
     710              :                 }
     711              :             }
     712           62 :         } else if (e->isBarLine()) {
     713           62 :         } else if (e->isClef()) {
     714              :             Segment* seg;
     715           18 :             if (remains == m->ticks() && m->tick() > Fraction(0, 1)) {
     716            0 :                 Measure* pm = m->prevMeasure();
     717            0 :                 seg = pm->getSegmentR(SegmentType::Clef, pm->ticks());
     718           18 :             } else if (remains != m->ticks()) {
     719            1 :                 seg = m->getSegmentR(SegmentType::Clef, m->ticks() - remains);
     720              :             } else {
     721           17 :                 seg = m->getSegmentR(SegmentType::HeaderClef, Fraction(0, 1));
     722              :             }
     723           18 :             EngravingItem* ne = e->clone();
     724           18 :             ne->setScore(score);
     725           18 :             ne->setTrack(m_track);
     726           18 :             seg->add(ne);
     727           44 :         } else if (e->isKeySig()) {
     728              :             Segment* seg;
     729              :             // No remains -> Next Measure if it does exist
     730            3 :             if ((remains == Fraction(0, 1)) && m->nextMeasure()) {
     731            0 :                 seg = m->nextMeasure()->getSegmentR(SegmentType::KeySig, Fraction(0, 1));
     732              :             } else {
     733            3 :                 seg = m->getSegmentR(SegmentType::KeySig, Fraction());
     734              :             }
     735            3 :             EngravingItem* ne = e->clone();
     736            3 :             ne->setScore(score);
     737            3 :             ne->setTrack(m_track);
     738            3 :             seg->add(ne);
     739              :         } else {
     740           41 :             if (!m) {
     741            0 :                 break;
     742              :             }
     743              :             // add the element in its own segment;
     744              :             // but KeySig has to be at start of (current) measure
     745              : 
     746           41 :             Segment* seg = m->getSegmentR(Segment::segmentType(e->type()), m->ticks() - remains);
     747           41 :             EngravingItem* ne = e->clone();
     748           41 :             ne->setScore(score);
     749           41 :             ne->setTrack(m_track);
     750           41 :             seg->add(ne);
     751              :         }
     752              :     }
     753              : 
     754              :     //
     755              :     // Rebuild Spanner's Start and End Notes
     756              :     //
     757           62 :     cloneAndRebuildSpanners(wClonedChord);
     758              : 
     759              :     //
     760              :     // connect ties from measure->first() to segment
     761              :     //
     762              : 
     763          591 :     for (Segment* s = measure->first(); s; s = s->next1()) {
     764          566 :         EngravingItem* e = s->element(m_track);
     765          566 :         if (!e || !e->isChord()) {
     766          260 :             continue;
     767              :         }
     768          306 :         Chord* chord = toChord(e);
     769          618 :         for (Note* n : chord->notes()) {
     770          312 :             Tie* tie = n->tieForNonPartial();
     771          312 :             if (!tie) {
     772          278 :                 continue;
     773              :             }
     774           34 :             Note* nn = searchTieNote(n);
     775           34 :             if (nn) {
     776           33 :                 tie->setEndNote(nn);
     777           33 :                 nn->setTieBack(tie);
     778              :             } else {
     779            1 :                 score->doUndoRemoveElement(tie);
     780              :             }
     781              :         }
     782          306 :         if (s == segment) {
     783           37 :             break;
     784              :         }
     785              :     }
     786           62 :     return true;
     787           63 : }
     788              : 
     789              : //---------------------------------------------------------
     790              : //   ScoreRange
     791              : //---------------------------------------------------------
     792              : 
     793           51 : ScoreRange::~ScoreRange()
     794              : {
     795           51 :     muse::DeleteAll(m_tracks);
     796           51 :     deleteBarLines();
     797           51 :     deleteSpacers();
     798           51 :     deleteJumpsAndMarkers();
     799           51 : }
     800              : 
     801              : //---------------------------------------------------------
     802              : //   read
     803              : //---------------------------------------------------------
     804              : 
     805           51 : void ScoreRange::read(Segment* first, Segment* last, bool readSpanner)
     806              : {
     807           51 :     m_first        = first;
     808           51 :     m_last         = last;
     809           51 :     Score* score  = first->score();
     810           51 :     std::vector<track_idx_t> sl = score->uniqueStaves();
     811              : 
     812           51 :     track_idx_t startTrack = 0;
     813           51 :     track_idx_t endTrack   = score->nstaves() * VOICES;
     814              : 
     815           51 :     m_spanner.clear();
     816              : 
     817           51 :     if (readSpanner) {
     818           51 :         Fraction stick = first->tick();
     819           51 :         Fraction etick = last->tick();
     820           91 :         for (auto i : first->score()->spanner()) {
     821           40 :             Spanner* s = i.second;
     822           40 :             if (s->systemFlag() && s->track() != 0) {
     823              :                 // Only process the top system object
     824            0 :                 continue;
     825              :             }
     826              : 
     827           40 :             if (s->tick() >= stick && s->tick() < etick && s->track() >= startTrack && s->track() < endTrack) {
     828           25 :                 Spanner* ns = toSpanner(s->clone());
     829           25 :                 ns->moveToDummy();
     830           25 :                 ns->setStartElement(0);
     831           25 :                 ns->setEndElement(0);
     832           25 :                 ns->setTick(ns->tick() - stick);
     833           25 :                 m_spanner.push_back(ns);
     834              :             }
     835              :         }
     836              :     }
     837           51 :     m_tracks.reserve(sl.size() * VOICES);
     838          110 :     for (track_idx_t staffIdx : sl) {
     839           59 :         track_idx_t sTrack = staffIdx * VOICES;
     840           59 :         track_idx_t eTrack = sTrack + VOICES;
     841          295 :         for (track_idx_t track = sTrack; track < eTrack; ++track) {
     842          236 :             TrackList* dl = new TrackList(this);
     843          236 :             dl->setTrack(track);
     844          236 :             dl->read(first, last);
     845          236 :             m_tracks.push_back(dl);
     846              :         }
     847              :     }
     848              : 
     849              :     // Make sure incoming ties are restored
     850           51 :     Measure* m1 = first->measure();
     851          287 :     for (track_idx_t track = startTrack; track < endTrack; track++) {
     852          236 :         Chord* startChord = m1->findChord(first->tick(), track);
     853          236 :         if (!startChord) {
     854          191 :             continue;
     855              :         }
     856           92 :         for (Note* note : startChord->notes()) {
     857           47 :             Tie* tie = note->tieBack();
     858           47 :             if (!tie) {
     859           44 :                 continue;
     860              :             }
     861            3 :             m_startTies.push_back(tie->clone());
     862            3 :             score->doUndoRemoveElement(tie);
     863              :         }
     864              :     }
     865              : 
     866           51 :     backupBarLines(first, last);
     867           51 :     backupBreaks(first, last);
     868           51 :     backupRepeats(first, last);
     869           51 :     backupSpacers(first, last);
     870           51 :     backupJumpsAndMarkers(first, last);
     871           51 : }
     872              : 
     873              : //---------------------------------------------------------
     874              : //   restoreVolta
     875              : //---------------------------------------------------------
     876              : 
     877            0 : void ScoreRange::restoreVolta(Score* score, const Fraction& tick, Volta* v) const
     878              : {
     879            0 :     bool voltaStartOK = false;
     880            0 :     bool voltaEndOK = false;
     881            0 :     Fraction measureSize;
     882              : 
     883            0 :     if (v->voltaType() == Volta::Type::OPEN) {
     884            0 :         voltaEndOK = true;
     885              :     }
     886              : 
     887              :     // Check if we should keep this volta
     888            0 :     for (Measure* m = score->tick2measure(tick); m; m = m->nextMeasure()) {
     889            0 :         if (m->tick() == (v->tick() + tick)) {
     890            0 :             voltaStartOK = true;
     891            0 :             measureSize = m->endTick() - m->tick();
     892              :         }
     893            0 :         if (m->endTick() == (v->tick2() + tick)) {
     894            0 :             voltaEndOK = true;
     895              :             // No need to continue looking for
     896            0 :             break;
     897              :         }
     898              :         // Last Measure
     899            0 :         if (m->sectionBreak() || (m->nextMeasure() && (m->nextMeasure()->first(SegmentType::TimeSig)))) {
     900            0 :             break;
     901              :         }
     902              :     }
     903            0 :     bool shouldKeepVolta = voltaStartOK && voltaEndOK;
     904              : 
     905            0 :     if (shouldKeepVolta) {
     906              :         // Volta start
     907            0 :         v->setTick(v->tick() + tick);
     908              : 
     909              :         // Review Volta endings with open Voltas
     910            0 :         if (v->voltaType() == Volta::Type::OPEN) {
     911            0 :             Fraction voltaFormerTicks = v->ticks();
     912            0 :             Fraction voltaNewTicks = voltaFormerTicks;
     913              : 
     914            0 :             if (voltaFormerTicks < measureSize) {
     915            0 :                 voltaNewTicks = measureSize;
     916            0 :             } else if (voltaFormerTicks > measureSize) {
     917            0 :                 if ((voltaFormerTicks / measureSize).reduced().denominator() != 1) {
     918            0 :                     voltaNewTicks = (std::floor((voltaFormerTicks / measureSize).toDouble()) + 1) * measureSize;
     919              :                 }
     920              :             }
     921            0 :             if (voltaFormerTicks != voltaNewTicks) {
     922            0 :                 v->setTicks(voltaNewTicks);
     923              :             }
     924              :         }
     925            0 :         score->undoAddElement(v);
     926              :     }
     927            0 : }
     928              : 
     929              : //---------------------------------------------------------
     930              : //   write
     931              : //---------------------------------------------------------
     932              : 
     933           51 : bool ScoreRange::write(Score* score, const Fraction& tick) const
     934              : {
     935          279 :     for (TrackList* dl : m_tracks) {
     936          229 :         track_idx_t track = dl->track();
     937          229 :         if (!dl->write(score, tick)) {
     938            1 :             return false;
     939              :         }
     940          228 :         if ((track % VOICES) == VOICES - 1) {
     941              :             // clone staff if appropriate after all voices have been copied
     942           57 :             staff_idx_t staffIdx = track / VOICES;
     943           57 :             Staff* ostaff = score->staff(staffIdx);
     944           57 :             const LinkedObjects* linkedStaves = ostaff->links();
     945           57 :             if (linkedStaves) {
     946            6 :                 for (auto le : *linkedStaves) {
     947            4 :                     Staff* nstaff = toStaff(le);
     948            4 :                     if (nstaff == ostaff) {
     949            2 :                         continue;
     950              :                     }
     951            2 :                     Excerpt::cloneStaff2(ostaff, nstaff, tick, (tick + dl->ticks()));
     952              :                 }
     953              :             }
     954              :         }
     955          228 :         ++track;
     956              :     }
     957           75 :     for (Spanner* s : m_spanner) {
     958           25 :         if (s->isVolta()) {
     959            0 :             restoreVolta(score, tick, toVolta(s));
     960            0 :             continue;
     961              :         }
     962           25 :         s->setTick(s->tick() + tick);
     963           25 :         if (s->isSlur()) {
     964           14 :             Slur* slur = toSlur(s);
     965           14 :             if (slur->startCR() && slur->startCR()->isGrace()) {
     966            0 :                 Chord* sc = slur->startChord();
     967            0 :                 size_t idx = sc->graceIndex();
     968            0 :                 Chord* dc = toChord(score->findCR(s->tick(), s->track()));
     969            0 :                 s->setStartElement(dc->graceNotes()[idx]);
     970              :             }
     971           14 :             if (slur->endCR() && slur->endCR()->isGrace()) {
     972            0 :                 Chord* sc = slur->endChord();
     973            0 :                 size_t idx = sc->graceIndex();
     974            0 :                 Chord* dc = toChord(score->findCR(s->tick2(), s->track2()));
     975            0 :                 s->setEndElement(dc->graceNotes()[idx]);
     976              :             }
     977              :         }
     978           25 :         if (s->anchor() == Spanner::Anchor::MEASURE) {
     979            0 :             Fraction startTick = s->tick();
     980            0 :             Measure* startMeasure = score->tick2measureMM(startTick);
     981            0 :             Fraction startMeasureTick = startMeasure->tick();
     982            0 :             Fraction endTick = s->tick2();
     983            0 :             Measure* endMeasure = score->tick2measureMM(endTick);
     984            0 :             Fraction endMeasureTick = endMeasure->tick();
     985            0 :             if (startMeasureTick != startTick) {
     986            0 :                 s->setTick(startMeasureTick);
     987              :             }
     988            0 :             if (endMeasureTick != endTick) {
     989            0 :                 s->setTick2(endMeasureTick != startMeasureTick ? endMeasureTick : endMeasure->endTick());
     990              :             }
     991              :         }
     992           25 :         score->undoAddElement(s);
     993              :     }
     994           64 :     for (const Annotation& a : m_annotations) {
     995           14 :         Measure* tm = score->tick2measure(a.tick);
     996           14 :         Segment* op = toSegment(a.e->ownershipParent());
     997           14 :         Fraction destTick = a.e->isRehearsalMark() ? tm->tick() : a.tick; // Ensure reharsal mark can only go at measure start
     998           14 :         Segment* s = tm->undoGetSegment(op->segmentType(), destTick);
     999           14 :         if (s) {
    1000           14 :             a.e->setOwnershipParent(s);
    1001           14 :             score->undoAddElement(a.e);
    1002              :         }
    1003              :     }
    1004              : 
    1005              :     // Restore ties to the beginning of the first measure
    1006           53 :     for (Tie* tie : m_startTies) {
    1007            3 :         Note* endNote = searchTieNote(tie->startNote());
    1008            3 :         if (!endNote) {
    1009            0 :             delete tie;
    1010            0 :             continue;
    1011              :         }
    1012            3 :         tie->setEndNote(endNote);
    1013            3 :         score->doUndoAddElement(tie);
    1014              :     }
    1015              : 
    1016           50 :     restoreBarLines(score, tick);
    1017           50 :     restoreBreaks(score, tick);
    1018           50 :     restoreRepeats(score, tick);
    1019           50 :     restoreSpacers(score, tick);
    1020           50 :     restoreJumpsAndMarkers(score, tick);
    1021           50 :     return true;
    1022              : }
    1023              : 
    1024              : //---------------------------------------------------------
    1025              : //   fill
    1026              : //---------------------------------------------------------
    1027              : 
    1028           18 : void ScoreRange::fill(const Fraction& f)
    1029              : {
    1030           18 :     const Fraction oldDuration = ticks();
    1031           18 :     Fraction oldEndTick = m_first->tick() + oldDuration;
    1032          114 :     for (auto t : m_tracks) {
    1033           96 :         t->appendGap(f, m_first->score());
    1034              :     }
    1035              : 
    1036           18 :     Fraction diff = ticks() - oldDuration;
    1037           22 :     for (Spanner* sp : m_spanner) {
    1038            4 :         if (sp->tick2() >= oldEndTick && sp->tick() < oldEndTick) {
    1039            3 :             sp->setTicks(sp->ticks() + diff);
    1040              :         }
    1041              :     }
    1042           18 : }
    1043              : 
    1044              : //---------------------------------------------------------
    1045              : //   truncate
    1046              : //    reduce len of last gap by f
    1047              : //---------------------------------------------------------
    1048              : 
    1049            0 : bool ScoreRange::truncate(const Fraction& f)
    1050              : {
    1051            0 :     for (TrackList* dl : m_tracks) {
    1052            0 :         if (dl->empty()) {
    1053            0 :             continue;
    1054              :         }
    1055            0 :         EngravingItem* e = dl->back();
    1056            0 :         if (!e->isRest()) {
    1057            0 :             return false;
    1058              :         }
    1059            0 :         Rest* r = toRest(e);
    1060            0 :         if (r->ticks() < f) {
    1061            0 :             return false;
    1062              :         }
    1063              :     }
    1064            0 :     for (TrackList* dl : m_tracks) {
    1065            0 :         dl->truncate(f);
    1066              :     }
    1067            0 :     return true;
    1068              : }
    1069              : 
    1070              : //---------------------------------------------------------
    1071              : //   ticks
    1072              : //---------------------------------------------------------
    1073              : 
    1074           71 : Fraction ScoreRange::ticks() const
    1075              : {
    1076           71 :     return m_tracks.empty() ? Fraction() : m_tracks.front()->ticks();
    1077              : }
    1078              : 
    1079              : //---------------------------------------------------------
    1080              : //   backupBarLines
    1081              : //---------------------------------------------------------
    1082           51 : void ScoreRange::backupBarLines(Segment* first, Segment* last)
    1083              : {
    1084          583 :     for (Segment* s = first; s && (s->isBefore(last) || s == last); s = s->next1()) {
    1085          532 :         if (!s->isType(SegmentType::BarLineTypes)) {
    1086          431 :             continue;
    1087              :         }
    1088          593 :         for (EngravingItem* e : s->elist()) {
    1089          492 :             if (e && !e->generated()) {
    1090           13 :                 BarLinesBackup blBackup;
    1091           13 :                 blBackup.sPosition = s->tick();
    1092           13 :                 blBackup.formerMeasureStartOrEnd = s->rtick().isZero() || s->rtick() == s->measure()->ticks();
    1093           13 :                 blBackup.bl = toBarLine(e)->clone();
    1094           13 :                 m_barLines.push_back(blBackup);
    1095              :             }
    1096              :         }
    1097              :     }
    1098           51 : }
    1099              : 
    1100              : //---------------------------------------------------------
    1101              : //   insertBarLine
    1102              : //---------------------------------------------------------
    1103           13 : bool ScoreRange::insertBarLine(Measure* m, const BarLinesBackup& barLine) const
    1104              : {
    1105              :     //---------------------------------------------------------
    1106              :     //   addBarLine
    1107              :     //---------------------------------------------------------
    1108           13 :     auto addBarLine = [&](Measure* m, BarLine* bl, SegmentType st, Fraction pos)
    1109              :     {
    1110           13 :         bool middle = (pos != m->tick()) && (pos != m->endTick());
    1111           13 :         Segment* seg = m->undoGetSegment(st, pos);
    1112           13 :         if (seg) {
    1113           13 :             BarLineType blt = bl->barLineType();
    1114              :             // get existing bar line if it does exist
    1115           13 :             BarLine* nbl = toBarLine(seg->element(bl->track()));
    1116           13 :             if (!nbl) {
    1117              :                 // no suitable bar line: create a new one
    1118           13 :                 nbl = Factory::createBarLine(seg);
    1119           13 :                 nbl->setOwnershipParent(seg);
    1120           13 :                 nbl->setTrack(bl->track());
    1121              :                 // A BL in the middle of a Measure does have SpanStaff to false
    1122           13 :                 nbl->setSpanStaff(middle ? false : bl->spanStaff());
    1123           13 :                 m->score()->addElement(nbl);
    1124              :             } else {
    1125              :                 // We change BarLineType if necessary to keep END_START repeats if in the middle of a meassure
    1126            0 :                 if ((nbl->barLineType() == BarLineType::END_REPEAT) && (bl->barLineType() == BarLineType::START_REPEAT) && middle) {
    1127            0 :                     blt = BarLineType::END_START_REPEAT;
    1128              :                 }
    1129              :             }
    1130           13 :             nbl->setGenerated(false);
    1131           13 :             nbl->setBarLineType(blt);
    1132           13 :             nbl->setVisible(bl->visible());
    1133           13 :             nbl->setColor(bl->color());
    1134              : 
    1135              :             // We check if the same BL type is in every Stave
    1136           13 :             bool blAcrossStaves = false;
    1137              :             // if there is only one stave or spanStaff
    1138           13 :             if ((m->score()->nstaves() == 1) || bl->spanStaff()) {
    1139           13 :                 blAcrossStaves = true;
    1140              :             }
    1141              :             // If we are in the last stave
    1142            0 :             else if (bl->staffIdx() == (m->score()->nstaves() - 1)) {
    1143            0 :                 bool sameBL = true;
    1144              :                 // We check if and every previous stave has the same type of BL
    1145            0 :                 for (size_t i = 0; i < (m->score()->nstaves() - 1); ++i) {
    1146            0 :                     BarLine* sbl = toBarLine(seg->element(staff2track(i)));
    1147            0 :                     if (!sbl || (sbl->barLineType() != blt)) {
    1148            0 :                         sameBL = false;
    1149            0 :                         break;
    1150              :                     }
    1151              :                 }
    1152            0 :                 blAcrossStaves = sameBL;
    1153              : 
    1154            0 :                 if (blAcrossStaves && !middle) {
    1155              :                     // Set Spanstaff to true if not in the middle and there is the same BL across staves
    1156            0 :                     for (size_t i = 0; i < (m->score()->nstaves() - 1); ++i) {
    1157            0 :                         BarLine* sbl = toBarLine(seg->element(staff2track(i)));
    1158            0 :                         if (sbl) {
    1159            0 :                             sbl->setSpanStaff(middle ? false : true);
    1160              :                         }
    1161              :                     }
    1162              :                 }
    1163              :             }
    1164              : 
    1165              :             // Adding Set repeats
    1166           13 :             if ((pos == m->tick()) && (bl->barLineType() == BarLineType::START_REPEAT) && blAcrossStaves) {
    1167            0 :                 m->setRepeatStart(true);
    1168           13 :             } else if ((pos == m->endTick()) && (bl->barLineType() == BarLineType::END_REPEAT) && blAcrossStaves) {
    1169            0 :                 m->setRepeatEnd(true);
    1170              :             }
    1171              :         }
    1172           13 :     };
    1173              : 
    1174           13 :     bool processed = false;
    1175              : 
    1176              :     // if END_START_REPEAT AND at the end of a Measure
    1177           13 :     if ((barLine.sPosition == m->endTick()) && (barLine.bl->barLineType() == BarLineType::END_START_REPEAT)) {
    1178              :         // Create END_REPEAT and START_REPEAT (and ignore return value)
    1179            0 :         barLine.bl->setBarLineType(BarLineType::END_REPEAT);
    1180            0 :         insertBarLine(m, barLine);
    1181              :         // Start Repeat into the next measure
    1182            0 :         if (m->nextMeasure()) {
    1183            0 :             barLine.bl->setBarLineType(BarLineType::START_REPEAT);
    1184            0 :             insertBarLine(m->nextMeasure(), barLine);
    1185              :         }
    1186              : 
    1187              :         // Restore initial value just in case
    1188            0 :         barLine.bl->setBarLineType(BarLineType::END_START_REPEAT);
    1189            0 :         processed = true;
    1190              :     } else {
    1191              :         // First position
    1192           13 :         if (barLine.sPosition == m->tick()) {
    1193              :             // Just Start Repeat at the left of the Measure
    1194            0 :             if (barLine.bl->barLineType() == BarLineType::START_REPEAT) {
    1195            0 :                 addBarLine(m, barLine.bl, SegmentType::StartRepeatBarLine, barLine.sPosition);
    1196            0 :                 processed = true;
    1197              :             }
    1198              :         }
    1199              :         // Last position
    1200           13 :         else if (barLine.sPosition == m->endTick()) {
    1201              :             // Avoid Start Repeat at the end of the Measure
    1202           13 :             if (barLine.bl->barLineType() != BarLineType::START_REPEAT) {
    1203           13 :                 addBarLine(m, barLine.bl, SegmentType::EndBarLine, barLine.sPosition);
    1204           13 :                 processed = true;
    1205              :             }
    1206              :         }
    1207              :         // Middle
    1208              :         else {
    1209              :             // We don't create BL in the Middle
    1210            0 :             processed = true;
    1211              :         }
    1212              :     }
    1213           13 :     return processed;
    1214              : }
    1215              : 
    1216              : //---------------------------------------------------------
    1217              : //   restoreBarLines
    1218              : //---------------------------------------------------------
    1219              : 
    1220           50 : void ScoreRange::restoreBarLines(Score* score, const Fraction& tick) const
    1221              : {
    1222           63 :     for (const BarLinesBackup& bbl : m_barLines) {
    1223           26 :         for (Measure* m = score->tick2measure(tick); m; m = m->nextMeasure()) {
    1224              :             // if inserted within a suitable measure ... to the next barline
    1225           26 :             if (((bbl.sPosition >= m->tick()) && (bbl.sPosition <= m->endTick())) && (insertBarLine(m, bbl))) {
    1226           13 :                 break;
    1227              :             }
    1228           13 :             if (m->tick() > bbl.sPosition) {
    1229            0 :                 break;
    1230              :             }
    1231              :         }
    1232              :     }
    1233           50 : }
    1234              : 
    1235              : //---------------------------------------------------------
    1236              : //   backupBreaks
    1237              : //---------------------------------------------------------
    1238           51 : void ScoreRange::backupBreaks(Segment* first, Segment* last)
    1239              : {
    1240           51 :     Measure* fm = first->measure();
    1241           51 :     Measure* lm = last->measure();
    1242          153 :     for (Measure* m = fm; m && m != lm->nextMeasure(); m = m->nextMeasure()) {
    1243          102 :         if (m->lineBreak()) {
    1244            0 :             BreaksBackup bBackup;
    1245            0 :             bBackup.sPosition = m->endTick();
    1246            0 :             bBackup.lBreakType = LayoutBreakType::LINE;
    1247            0 :             m_breaks.push_back(bBackup);
    1248          102 :         } else if (m->pageBreak()) {
    1249            0 :             BreaksBackup bBackup;
    1250            0 :             bBackup.sPosition = m->endTick();
    1251            0 :             bBackup.lBreakType = LayoutBreakType::PAGE;
    1252            0 :             m_breaks.push_back(bBackup);
    1253              :         }
    1254              :     }
    1255           51 : }
    1256              : 
    1257              : //---------------------------------------------------------
    1258              : //   restoreBreaks
    1259              : //---------------------------------------------------------
    1260              : 
    1261           50 : void ScoreRange::restoreBreaks(Score* score, const Fraction& tick) const
    1262              : {
    1263              :     // Break list
    1264           50 :     for (const BreaksBackup& bb : m_breaks) {
    1265              :         // Look for suitable measure
    1266            0 :         for (Measure* m = score->tick2measure(tick); m; m = m->nextMeasure()) {
    1267              :             // We keep them as long as they are in the measure after the start tick
    1268            0 :             if ((bb.sPosition > m->tick()) && (bb.sPosition <= m->endTick())) {
    1269            0 :                 m->undoSetBreak(true, bb.lBreakType);
    1270            0 :                 break;
    1271              :             }
    1272            0 :             if (m->tick() > bb.sPosition) {
    1273            0 :                 break;
    1274              :             }
    1275              :         }
    1276              :     }
    1277           50 : }
    1278              : 
    1279           51 : void ScoreRange::backupRepeats(Segment* first, Segment* last)
    1280              : {
    1281           51 :     Measure* fm = first->measure();
    1282           51 :     Measure* lm = last->measure();
    1283          153 :     for (Measure* m = fm; m && m != lm->nextMeasure(); m = m->nextMeasure()) {
    1284          102 :         if (m->repeatStart()) {
    1285            1 :             StartEndRepeatBackup repeatBackup;
    1286            1 :             repeatBackup.sPosition = m->tick();
    1287            1 :             repeatBackup.isStartRepeat = true;
    1288            1 :             m_startEndRepeats.push_back(repeatBackup);
    1289              :         }
    1290          102 :         if (m->repeatEnd()) {
    1291            1 :             StartEndRepeatBackup repeatBackup;
    1292            1 :             repeatBackup.sPosition = m->endTick();
    1293            1 :             repeatBackup.isStartRepeat = false;
    1294            1 :             m_startEndRepeats.push_back(repeatBackup);
    1295              :         }
    1296              :     }
    1297           51 : }
    1298              : 
    1299           50 : void ScoreRange::restoreRepeats(Score* score, const Fraction& tick) const
    1300              : {
    1301           50 :     Fraction refTick = tick.isZero() ? tick : tick - Fraction::eps(); // start checking one measure before
    1302           52 :     for (const StartEndRepeatBackup& startEndRepeat : m_startEndRepeats) {
    1303           19 :         for (Measure* m = score->tick2measure(refTick); m; m = m->nextMeasure()) {
    1304           19 :             Fraction mTick = m->tick();
    1305           19 :             if (startEndRepeat.isStartRepeat && startEndRepeat.sPosition == mTick) {
    1306            1 :                 m->undoChangeProperty(Pid::REPEAT_START, true);
    1307           18 :             } else if (!startEndRepeat.isStartRepeat && startEndRepeat.sPosition == m->endTick()) {
    1308            0 :                 m->undoChangeProperty(Pid::REPEAT_END, true);
    1309              :             }
    1310           19 :             if (mTick > startEndRepeat.sPosition) {
    1311            2 :                 break;
    1312              :             }
    1313              :         }
    1314              :     }
    1315           50 : }
    1316              : 
    1317              : //---------------------------------------------------------
    1318              : //   deleteBarLines
    1319              : //---------------------------------------------------------
    1320              : 
    1321           51 : void ScoreRange::deleteBarLines()
    1322              : {
    1323           64 :     for (const BarLinesBackup& bbl : m_barLines) {
    1324           13 :         delete bbl.bl;
    1325              :     }
    1326           51 :     m_barLines.clear();
    1327           51 : }
    1328              : 
    1329              : //---------------------------------------------------------
    1330              : //   backupSpacers
    1331              : //---------------------------------------------------------
    1332              : 
    1333           51 : void ScoreRange::backupSpacers(Segment* first, Segment* last)
    1334              : {
    1335           51 :     Measure* fm = first->measure();
    1336           51 :     Measure* lm = last->measure();
    1337              : 
    1338          153 :     for (Measure* m = fm; m && m != lm->nextMeasure(); m = m->nextMeasure()) {
    1339          102 :         staff_idx_t nStaves = m->score()->nstaves();
    1340              : 
    1341          223 :         for (staff_idx_t i = 0; i < nStaves; ++i) {
    1342          121 :             if (m->vspacerUp(i)) {
    1343            0 :                 SpacerBackup sb;
    1344            0 :                 sb.s = m->vspacerUp(i)->clone();
    1345            0 :                 sb.sPosition = m->tick() + ((m->endTick() - m->tick()) / 2);
    1346            0 :                 sb.staffIdx = i;
    1347            0 :                 m_spacers.push_back(sb);
    1348              :             }
    1349          121 :             if (m->vspacerDown(i)) {
    1350            0 :                 SpacerBackup sb;
    1351            0 :                 sb.s = m->vspacerDown(i)->clone();
    1352            0 :                 sb.sPosition = m->tick() + ((m->endTick() - m->tick()) / 2);
    1353            0 :                 sb.staffIdx = i;
    1354            0 :                 m_spacers.push_back(sb);
    1355              :             }
    1356              :         }
    1357              :     }
    1358           51 : }
    1359              : 
    1360              : //---------------------------------------------------------
    1361              : //   restoreSpacers
    1362              : //---------------------------------------------------------
    1363           50 : void ScoreRange::restoreSpacers(Score* score, const Fraction& tick) const
    1364              : {
    1365              :     //---------------------------------------------------------
    1366              :     //   addSpacer
    1367              :     //---------------------------------------------------------
    1368            0 :     auto addSpacer = [&](Measure* m, Spacer* s, staff_idx_t staffIdx)
    1369              :     {
    1370              :         // We only add an element if there isn't a previous one of the same Type (UP/DOWN)
    1371            0 :         if ((s->spacerType() == SpacerType::UP && !m->vspacerUp(staffIdx))
    1372            0 :             || ((s->spacerType() == SpacerType::DOWN || s->spacerType() == SpacerType::FIXED) && !m->vspacerDown(staffIdx))) {
    1373            0 :             Spacer* ns = Factory::createSpacer(m);
    1374            0 :             ns->setSpacerType(s->spacerType());
    1375            0 :             ns->setGap(s->gap());
    1376            0 :             ns->setTrack(staffIdx * VOICES);
    1377            0 :             m->add(ns);
    1378              :         }
    1379            0 :     };
    1380              : 
    1381              :     // Spacers list
    1382           50 :     for (const SpacerBackup& sb : m_spacers) {
    1383              :         // Look for suitable measure
    1384            0 :         for (Measure* m = score->tick2measure(tick); m; m = m->nextMeasure()) {
    1385            0 :             if (sb.sPosition >= m->tick() && sb.sPosition <= m->endTick()) {
    1386            0 :                 addSpacer(m, sb.s, sb.staffIdx);
    1387            0 :                 break;
    1388              :             }
    1389            0 :             if (m->tick() > sb.sPosition) {
    1390            0 :                 break;
    1391              :             }
    1392              :         }
    1393              :     }
    1394           50 : }
    1395              : 
    1396              : //---------------------------------------------------------
    1397              : //   deleteSpacers
    1398              : //---------------------------------------------------------
    1399           51 : void ScoreRange::deleteSpacers()
    1400              : {
    1401              :     // Spacers list
    1402           51 :     for (const SpacerBackup& sb : m_spacers) {
    1403            0 :         delete sb.s;
    1404              :     }
    1405           51 :     m_spacers.clear();
    1406           51 : }
    1407              : 
    1408              : //---------------------------------------------------------
    1409              : //   endOfMeasureElement
    1410              : //---------------------------------------------------------
    1411              : 
    1412            0 : bool ScoreRange::endOfMeasureElement(EngravingItem* e) const
    1413              : {
    1414            0 :     bool result = false;
    1415              : 
    1416            0 :     if (e->isMarker()
    1417            0 :         && ((muse::contains(Marker::RIGHT_MARKERS, toMarker(e)->markerType()) || toMarker(e)->markerType() == MarkerType::FINE))) {
    1418            0 :         result = true;
    1419            0 :     } else if (e->isJump()) {
    1420            0 :         result = true;
    1421              :     }
    1422            0 :     return result;
    1423              : }
    1424              : 
    1425              : //---------------------------------------------------------
    1426              : //   backupJumpsAndMarkers
    1427              : //---------------------------------------------------------
    1428              : 
    1429           51 : void ScoreRange::backupJumpsAndMarkers(Segment* first, Segment* last)
    1430              : {
    1431           51 :     Measure* fm = first->measure();
    1432           51 :     Measure* lm = last->measure();
    1433              : 
    1434          153 :     for (Measure* m = fm; m && m != lm->nextMeasure(); m = m->nextMeasure()) {
    1435              :         // Backup Markers and Jumps (Measures's son)
    1436          102 :         for (EngravingItem* e : m->el()) {
    1437            0 :             if (e && (e->isMarker() || e->isJump())) {
    1438            0 :                 JumpsMarkersBackup mJMBackup;
    1439            0 :                 mJMBackup.sPosition = (endOfMeasureElement(e) ? m->endTick() : m->tick());
    1440            0 :                 mJMBackup.e = e->clone();
    1441            0 :                 m_jumpsMarkers.push_back(mJMBackup);
    1442              :             }
    1443              :         }
    1444              :     }
    1445           51 : }
    1446              : 
    1447              : //---------------------------------------------------------
    1448              : //   restoreJumpsAndMarkers
    1449              : //---------------------------------------------------------
    1450           50 : void ScoreRange::restoreJumpsAndMarkers(Score* score, const Fraction& tick) const
    1451              : {
    1452              :     //---------------------------------------------------------
    1453              :     //   addJumpMarker
    1454              :     //---------------------------------------------------------
    1455            0 :     auto addJumpMarker = [&](Measure* m, EngravingItem* e)
    1456              :     {
    1457              :         // We add every element as a Measure could have as many elements (even of the same type) as the users decides
    1458            0 :         EngravingItem* ce = e->clone();
    1459            0 :         ce->setOwnershipParent(m);
    1460            0 :         ce->setTrack(0);
    1461            0 :         m->add(ce);
    1462            0 :     };
    1463              : 
    1464           50 :     for (const JumpsMarkersBackup& jmb : m_jumpsMarkers) {
    1465            0 :         for (Measure* m = score->tick2measure(tick); m; m = m->nextMeasure()) {
    1466              :             // Markers: we keep them as long as they are in the measure before the final tick
    1467              :             // Jumps: we keep them as long as they are in the measure after the start tick
    1468            0 :             if ((endOfMeasureElement(jmb.e) && jmb.sPosition > m->tick() && jmb.sPosition <= m->endTick())
    1469            0 :                 || (!endOfMeasureElement(jmb.e) && jmb.sPosition >= m->tick() && jmb.sPosition < m->endTick())) {
    1470            0 :                 addJumpMarker(m, jmb.e);
    1471            0 :                 LOGI() << "tpacebes hago restore";
    1472              :             }
    1473            0 :             if (m->tick() > jmb.sPosition) {
    1474            0 :                 break;
    1475              :             }
    1476              :         }
    1477              :     }
    1478           50 : }
    1479              : 
    1480              : //---------------------------------------------------------
    1481              : //   deleteJumpsAndMarkers
    1482              : //---------------------------------------------------------
    1483              : 
    1484           51 : void ScoreRange::deleteJumpsAndMarkers()
    1485              : {
    1486           51 :     for (const JumpsMarkersBackup& jmb : m_jumpsMarkers) {
    1487            0 :         delete jmb.e;
    1488              :     }
    1489           51 :     m_jumpsMarkers.clear();
    1490           51 : }
    1491              : 
    1492              : //---------------------------------------------------------
    1493              : //   dump
    1494              : //---------------------------------------------------------
    1495              : 
    1496            0 : void TrackList::dump() const
    1497              : {
    1498            0 :     LOGD("elements %zu, duration %d/%d", size(), m_duration.numerator(), m_duration.denominator());
    1499            0 :     for (EngravingItem* e : *this) {
    1500            0 :         if (e->isDurationElement()) {
    1501            0 :             Fraction du = toDurationElement(e)->ticks();
    1502            0 :             LOGD("   %s  %d/%d", e->typeName(), du.numerator(), du.denominator());
    1503              :         } else {
    1504            0 :             LOGD("   %s", e->typeName());
    1505              :         }
    1506              :     }
    1507            0 : }
    1508              : }
        

Generated by: LCOV version 2.0-1