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 : }
|