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 "repeatlist.h"
24 :
25 : #include <list>
26 : #include <set>
27 : #include <utility> // std::pair
28 :
29 : #include "jump.h"
30 : #include "layoutbreak.h"
31 : #include "marker.h"
32 : #include "measure.h"
33 : #include "score.h"
34 : #include "volta.h"
35 :
36 : #include "global/realfn.h"
37 : #include "global/log.h"
38 :
39 : using namespace mu;
40 :
41 : namespace mu::engraving {
42 : //---------------------------------------------------------
43 : // RepeatSegment
44 : //---------------------------------------------------------
45 :
46 2616 : RepeatSegment::RepeatSegment(int playbackCount)
47 2616 : : tick(0), utick(0), pause(0.0), playbackCount(playbackCount)
48 : {
49 2616 : }
50 :
51 6313 : void RepeatSegment::addMeasure(Measure const* const m)
52 : {
53 6313 : if (m != nullptr) {
54 6313 : if (m_measureList.empty()) {
55 3632 : tick = m->tick().ticks();
56 : }
57 6313 : if ((m_measureList.empty()) || (m_measureList.back() != m)) {
58 6313 : m_measureList.push_back(m);
59 : }
60 : }
61 6313 : }
62 :
63 : /// \brief Expands or clips my measureList up to m (including m)
64 3697 : void RepeatSegment::addMeasures(Measure const* const m)
65 : {
66 3697 : if (!m_measureList.empty()) {
67 : // Add up to the current measure, final measure is added outside of this condition
68 3697 : Measure const* lastMeasure = m_measureList.back()->nextMeasureMM();
69 3697 : if (lastMeasure && (lastMeasure->tick() < m->tick())) { // Ensure provided reference is later than current last
70 11867 : while (lastMeasure && lastMeasure != m) {
71 10578 : m_measureList.push_back(lastMeasure);
72 10578 : lastMeasure = lastMeasure->nextMeasureMM();
73 : }
74 : }
75 : //else { // Possibly clip compared to current last measure }
76 4933 : while (!m_measureList.empty() && (m_measureList.back()->tick() >= m->tick())) {
77 1236 : m_measureList.pop_back();
78 : }
79 : }
80 3697 : addMeasure(m);
81 3697 : }
82 :
83 3856 : bool RepeatSegment::containsMeasure(Measure const* const m) const
84 : {
85 24806 : for (Measure const* const measure : m_measureList) {
86 24592 : if (measure == m) {
87 3642 : return true;
88 : }
89 : }
90 214 : return false;
91 : }
92 :
93 42539 : bool RepeatSegment::endsWithMeasure(Measure const* const m) const
94 : {
95 42539 : if (m_measureList.empty()) {
96 0 : return false;
97 : }
98 :
99 42539 : return m_measureList.back() == m;
100 : }
101 :
102 53 : bool RepeatSegment::startsWithMeasure(const Measure* const m) const
103 : {
104 53 : if (m_measureList.empty()) {
105 0 : return false;
106 : }
107 :
108 53 : return m_measureList.front() == m;
109 : }
110 :
111 2616 : bool RepeatSegment::isEmpty() const
112 : {
113 2616 : return m_measureList.empty();
114 : }
115 :
116 5257 : int RepeatSegment::len() const
117 : {
118 5257 : return (m_measureList.empty()) ? 0 : (m_measureList.back()->endTick().ticks() - tick);
119 : }
120 :
121 1901 : int RepeatSegment::endTick() const
122 : {
123 1901 : return tick + len();
124 : }
125 :
126 258 : void RepeatSegment::popMeasure()
127 : {
128 258 : if (!m_measureList.empty()) {
129 258 : m_measureList.pop_back();
130 : }
131 258 : }
132 :
133 599 : const std::vector<const Measure*>& RepeatSegment::measureList() const
134 : {
135 599 : return m_measureList;
136 : }
137 :
138 698 : bool operator==(const RepeatSegment& lhs, const RepeatSegment& rhs)
139 : {
140 698 : if (lhs.m_measureList.size() != rhs.m_measureList.size()) {
141 314 : return false;
142 : }
143 3974 : for (size_t i = 0; i < lhs.m_measureList.size(); i++) {
144 3591 : if (lhs.m_measureList.at(i) != rhs.m_measureList.at(i)) {
145 1 : return false;
146 : }
147 : }
148 383 : return lhs.tick == rhs.tick
149 383 : && lhs.utick == rhs.utick
150 383 : && muse::RealIsEqual(lhs.pause, rhs.pause)
151 766 : && lhs.playbackCount == rhs.playbackCount;
152 : }
153 :
154 : //---------------------------------------------------------
155 : // RepeatList
156 : //---------------------------------------------------------
157 :
158 4338 : RepeatList::RepeatList(Score* s)
159 : {
160 4338 : m_score = s;
161 4338 : m_utick2tickHint = 0;
162 4338 : }
163 :
164 : //---------------------------------------------------------
165 : // ~RepeatList
166 : //---------------------------------------------------------
167 :
168 3888 : RepeatList::~RepeatList()
169 : {
170 3888 : muse::DeleteAll(*this);
171 3888 : }
172 :
173 : //---------------------------------------------------------
174 : // ticks
175 : //---------------------------------------------------------
176 :
177 0 : int RepeatList::ticks() const
178 : {
179 0 : if (size() > 0) {
180 0 : const RepeatSegment* s = back();
181 0 : return s->utick + s->len();
182 : }
183 0 : return 0;
184 : }
185 :
186 : //---------------------------------------------------------
187 : // update
188 : //---------------------------------------------------------
189 :
190 37886 : void RepeatList::update(bool expand, bool updateTies)
191 : {
192 37886 : if (!m_scoreChanged && expand == m_expanded) {
193 36079 : return;
194 : }
195 :
196 1807 : std::vector<RepeatSegment> oldSegments;
197 1807 : oldSegments.reserve(size());
198 2534 : for (RepeatSegment* rs : *this) {
199 727 : oldSegments.push_back(*rs);
200 : }
201 :
202 1807 : if (expand) {
203 1807 : unwind();
204 : } else {
205 0 : flatten();
206 : }
207 :
208 1807 : bool structureChanged = (oldSegments.size() != size());
209 1807 : if (!structureChanged) {
210 967 : for (size_t i = 0; i < size(); ++i) {
211 698 : if (!(oldSegments[i] == *at(i))) {
212 315 : structureChanged = true;
213 315 : break;
214 : }
215 : }
216 : }
217 :
218 1807 : m_scoreChanged = false;
219 :
220 1807 : if (updateTies && structureChanged) {
221 0 : m_score->undoRemoveStaleTieJumpPoints();
222 : }
223 1807 : }
224 :
225 1759 : void RepeatList::updateUticks()
226 : {
227 1759 : int utick = 0;
228 :
229 4317 : for (RepeatSegment* s : *this) {
230 2558 : s->utick = utick;
231 2558 : utick += s->len();
232 : }
233 1759 : }
234 :
235 : //---------------------------------------------------------
236 : // utick2tick
237 : //---------------------------------------------------------
238 :
239 13 : int RepeatList::utick2tick(int tick) const
240 : {
241 13 : size_t n = size();
242 13 : if (n == 0) {
243 0 : return tick;
244 : }
245 13 : if (tick < 0) {
246 0 : return 0;
247 : }
248 13 : unsigned ii = (m_utick2tickHint < n) && (tick >= at(m_utick2tickHint)->utick) ? m_utick2tickHint : 0;
249 13 : for (unsigned i = ii; i < n; ++i) {
250 13 : if ((tick >= at(i)->utick) && ((i + 1 == n) || (tick < at(i + 1)->utick))) {
251 13 : m_utick2tickHint = i;
252 13 : return tick - (at(i)->utick - at(i)->tick);
253 : }
254 : }
255 :
256 0 : ASSERT_X(String(u"tick %1 not found in RepeatList").arg(tick));
257 : return 0;
258 : }
259 :
260 : //---------------------------------------------------------
261 : // tick2utick
262 : //---------------------------------------------------------
263 :
264 7 : int RepeatList::tick2utick(int tick) const
265 : {
266 7 : if (empty()) {
267 0 : return 0;
268 : }
269 7 : for (const RepeatSegment* s : *this) {
270 7 : if (tick >= s->tick && tick < s->endTick()) {
271 7 : return s->utick + (tick - s->tick);
272 : }
273 : }
274 0 : return back()->utick + (tick - back()->tick);
275 : }
276 :
277 : ///
278 : /// \brief Lookup the RepeatSegment containing the given utick
279 : ///
280 582 : std::vector<RepeatSegment*>::const_iterator RepeatList::findRepeatSegmentFromUTick(int utick) const
281 : {
282 617 : for (auto it = cbegin(); it != cend(); ++it) {
283 617 : const RepeatSegment* seg = *it;
284 617 : if (utick >= seg->utick && utick < seg->utick + seg->len()) {
285 582 : return it;
286 : }
287 : }
288 :
289 0 : return cend();
290 : }
291 :
292 487 : std::vector<RepeatSegmentInfo> RepeatList::segmentInfoList() const
293 : {
294 487 : std::vector<RepeatSegmentInfo> result;
295 487 : result.reserve(size());
296 :
297 941 : for (const RepeatSegment* seg : *this) {
298 454 : result.push_back({ seg->tick, seg->endTick(), seg->utick });
299 : }
300 :
301 487 : return result;
302 0 : }
303 :
304 : //---------------------------------------------------------
305 : // flatten
306 : /// Make this repeat list flat (don't expand repeats)
307 : //---------------------------------------------------------
308 :
309 0 : void RepeatList::flatten()
310 : {
311 0 : muse::DeleteAll(*this);
312 0 : clear();
313 :
314 0 : Measure* m = m_score->firstMeasureMM();
315 0 : if (!m) {
316 0 : return;
317 : }
318 :
319 0 : RepeatSegment* s = new RepeatSegment(1);
320 : do {
321 0 : s->addMeasure(m);
322 0 : m = m->nextMeasureMM();
323 0 : } while (m);
324 0 : push_back(s);
325 :
326 0 : m_expanded = false;
327 : }
328 :
329 : //---------------------------------------------------------
330 : // unwind
331 : // implements:
332 : // - repeats
333 : // - volta
334 : // - d.c. al fine
335 : // - d.s. al fine
336 : // - d.s. al coda
337 : //---------------------------------------------------------
338 : enum class RepeatListElementType : unsigned char {
339 : SECTION_BREAK,
340 : VOLTA_START,
341 : VOLTA_END,
342 : REPEAT_START,
343 : REPEAT_END,
344 : JUMP,
345 : MARKER
346 : };
347 :
348 : class RepeatListElement
349 : {
350 : public:
351 : RepeatListElementType const repeatListElementType;
352 : EngravingItem const* const element;
353 : Measure const* const measure; // convenience, should be measure containing element
354 : private:
355 : int repeatCount;
356 :
357 : public:
358 4939 : RepeatListElement(RepeatListElementType type, EngravingItem const* const el, Measure const* const m)
359 4939 : : repeatListElementType(type), element(el), measure(m)
360 : {
361 4939 : repeatCount = (type == RepeatListElementType::REPEAT_START) ? 1 : 0;
362 4939 : }
363 :
364 1429 : ~RepeatListElement()
365 : {
366 : // Voltas are cloned elements, we need to cleanup ourselves
367 1429 : if (repeatListElementType == RepeatListElementType::VOLTA_START) {
368 58 : delete element;
369 : }
370 1429 : }
371 :
372 1587 : int getRepeatCount() const { return repeatCount; }
373 1011 : void addToRepeatCount(int add) { repeatCount += add; }
374 : };
375 :
376 : ///---------------------------------------------------------
377 : /// \brief Collects all RepeatListElementType elements in the score
378 : /// \details Those are the only type of elements that actually influence playback order
379 : ///---------------------------------------------------------
380 1759 : void RepeatList::collectRepeatListElements()
381 : {
382 1759 : RepeatListElementList sectionRLElements;
383 :
384 : // Clear out previous listing
385 2327 : for (const RepeatListElementList& srle : m_rlElements) {
386 568 : muse::DeleteAll(srle);
387 : }
388 1759 : m_rlElements.clear();
389 :
390 1759 : RepeatListElement* startFromRepeatMeasure = nullptr;
391 :
392 : // Section breaks may occur on non-Measure frames, so must search list of all MeasureBases
393 : // unwinding itself will only use actual Measures
394 1759 : MeasureBase* mb = m_score->firstMeasureMM();
395 : // First measure of a section/score is always used as a reference REPEAT_START point
396 : // even if it doesn't have a start repeat
397 1759 : startFromRepeatMeasure = new RepeatListElement(RepeatListElementType::REPEAT_START, mb, toMeasure(mb));
398 1759 : sectionRLElements.push_back(startFromRepeatMeasure);
399 : // Also trace down the final actual measure of this section (in case a frame follows)
400 1759 : MeasureBase* sectionEndMeasureBase = nullptr;
401 : // Used to track voltas; overlappings and real endings
402 : Volta* volta;
403 1759 : std::list<Volta*> preProcessedVoltas;
404 :
405 : // Voltas might overlap (duplicate entries on multiple staves or "real" overlaps)
406 : // so we will pre-process them into cloned versions that handle those overlaps.
407 : // This assumes that spanners are ordered from first to last tick-wise
408 3048 : for (const auto& spannerEntry : m_score->spanner()) {
409 1289 : if (!spannerEntry.second->isVolta() || !spannerEntry.second->playSpanner()) {
410 1055 : continue;
411 : }
412 :
413 234 : if (!spannerEntry.second->startMeasure() || !spannerEntry.second->endMeasure()) {
414 16 : continue;
415 : }
416 :
417 218 : volta = toVolta(spannerEntry.second)->clone();
418 :
419 218 : if (preProcessedVoltas.empty()) { // First entry
420 92 : preProcessedVoltas.push_back(volta);
421 : } else { // Compare
422 126 : std::list<Volta*> voltasToMerge;
423 126 : Fraction startMeasureTick = volta->startMeasure()->tick();
424 :
425 : // List all overlapping voltas
426 138 : while ((!preProcessedVoltas.empty())
427 138 : && (startMeasureTick <= preProcessedVoltas.back()->endMeasure()->tick())
428 : ) {
429 12 : voltasToMerge.push_back(preProcessedVoltas.back());
430 12 : preProcessedVoltas.pop_back();
431 : }
432 :
433 138 : while (!voltasToMerge.empty()) {
434 : // We'll have to shorten the already stored volta and split its remainder for merging
435 12 : Volta* remainder = voltasToMerge.back()->clone();
436 12 : if (volta->startMeasure() != remainder->startMeasure()) {
437 : // First part is not empty
438 5 : voltasToMerge.back()->setEndElement(volta->startMeasure()->prevMeasureMM());
439 5 : remainder->setStartElement(volta->startMeasure());
440 : // Store it
441 5 : preProcessedVoltas.push_back(voltasToMerge.back());
442 : }
443 : //else { New volta and existing one start at the same moment, there is no first part, only a remainder }
444 12 : voltasToMerge.pop_back();
445 :
446 : // remainder and volta now have the same start point
447 : // Compare the end points and make remainder end first
448 12 : if (volta->endMeasure()->tick() < remainder->endMeasure()->tick()) {
449 3 : Volta* swap = volta;
450 3 : volta = remainder;
451 3 : remainder = swap;
452 : }
453 : // Cross-section of the repeatList
454 12 : std::vector<int> endings = remainder->endings();
455 12 : muse::remove_if(endings, [&volta](const int& ending) {
456 20 : return !(volta->hasEnding(ending));
457 : });
458 :
459 12 : remainder->setEndings(endings);
460 : // Split and merge done
461 12 : preProcessedVoltas.push_back(remainder);
462 12 : if (volta->endMeasure() != remainder->endMeasure()) {
463 : // volta extends past the end of remainder -> move its startpoint after remainder
464 6 : volta->setStartElement(remainder->endMeasure()->nextMeasureMM());
465 : } else { // volta matched remainder endpoint, nothing left to merge from
466 6 : preProcessedVoltas.splice(preProcessedVoltas.cend(), voltasToMerge);
467 6 : delete volta;
468 6 : volta = nullptr;
469 : }
470 12 : } // !voltasToMerge.empty()
471 :
472 126 : if (volta != nullptr) {
473 120 : preProcessedVoltas.push_back(volta);
474 : }
475 126 : }
476 : }
477 :
478 1759 : volta = nullptr;
479 14470 : for (; mb; mb = mb->nextMM()) {
480 14470 : if (mb->isMeasure()) {
481 14398 : Measure* m = toMeasure(mb);
482 14398 : sectionEndMeasureBase = mb; // ending measure of section is the most recently encountered actual Measure
483 14398 : Measure* underlyingMeasure = m->isMMRest() ? m->mmRestFirst() : m;
484 :
485 : // Volta ?
486 14398 : if ((!preProcessedVoltas.empty()) && (preProcessedVoltas.front()->startMeasure() == underlyingMeasure)) {
487 217 : if (volta != nullptr) {
488 : //if (volta->endMeasure()->tick() < m->tick()) {
489 : // The previous volta was supposed to end before us (open volta case) -> insert the end
490 5 : sectionRLElements.push_back(new RepeatListElement(RepeatListElementType::VOLTA_END, volta, m->prevMeasureMM()));
491 : //volta = nullptr; // No need, replaced immediately further down
492 : // }
493 : //else { // Overlapping voltas; this should not happen as preProcessedVoltas should've dealt with this already }
494 : }
495 : // Now insert the start of the current volta
496 217 : volta = preProcessedVoltas.front();
497 217 : sectionRLElements.push_back(new RepeatListElement(RepeatListElementType::VOLTA_START, volta, m));
498 : // Look for start of next volta
499 217 : preProcessedVoltas.pop_front();
500 : }
501 : // Start
502 14398 : if (m->repeatStart()) {
503 169 : if (volta != nullptr) {
504 7 : if (volta->startMeasure() != underlyingMeasure) {
505 : // Volta and Start repeat are not on the same measure
506 : // assume the previous volta was supposed to end before us (open volta case) -> insert the end
507 : // Warning: This might "break" a volta prematurely if its explicit notated end is later than this point
508 : // Consider splitting the volta or ignoring this repeat all together
509 5 : sectionRLElements.push_back(new RepeatListElement(RepeatListElementType::VOLTA_END, volta, m->prevMeasureMM()));
510 5 : volta = nullptr;
511 : }
512 : //else { // Volta and Start Repeat coincide on the same measure, see test::repeat56.mscx }
513 : }
514 169 : startFromRepeatMeasure = new RepeatListElement(RepeatListElementType::REPEAT_START, m, m);
515 169 : sectionRLElements.push_back(startFromRepeatMeasure);
516 : }
517 : // Jumps and Markers
518 16167 : for (EngravingItem* e : m->el()) {
519 1769 : if (e->systemFlag() && !e->isTopSystemObject()) {
520 2 : continue;
521 : }
522 :
523 1767 : if (e->isJump()) {
524 188 : sectionRLElements.push_back(new RepeatListElement(RepeatListElementType::JUMP, e, m));
525 188 : if (volta != nullptr) {
526 22 : if ((volta->endMeasure()->tick() < m->tick())
527 57 : || ((volta->endMeasure()->tick() == m->tick())
528 35 : && (volta->getProperty(Pid::END_HOOK_TYPE).value<HookType>() == HookType::NONE)
529 : )
530 : ) {
531 : // The previous volta was supposed to end before us
532 : // or open volta ends together with us -> insert the end
533 8 : if (!m->repeatEnd()) {
534 : // But only do so if this measure doesn't also have an end repeat: see #327681
535 7 : sectionRLElements.push_back(new RepeatListElement(RepeatListElementType::VOLTA_END, volta, m));
536 7 : volta = nullptr;
537 : }
538 : //else {
539 : // The measure also has an end repeat which should be included in the volta
540 : // We can't abort the volta here, and leave it to the end repeat to do so
541 : //}
542 : }
543 : //else { // Volta is spanning past this jump instruction }
544 : }
545 1579 : } else if (e->isMarker()) {
546 273 : RepeatListElement* markerRLE = new RepeatListElement(RepeatListElementType::MARKER, e, m);
547 : // There may be multiple markers in the same measure. Make sure we place right markers before left
548 : // At the same time, we should ensure Markers are evaluated before Jumps
549 273 : bool markerRLEisRight = toMarker(e)->isRightMarker();
550 273 : auto insertionIt = sectionRLElements.end() - 1;
551 275 : while ((*insertionIt)->measure == markerRLE->measure) {
552 52 : bool markerShouldGoBefore = false;
553 52 : if (((*insertionIt)->repeatListElementType == RepeatListElementType::MARKER)
554 52 : && (!markerRLEisRight) // We can be the end when right aligned
555 : ) {
556 2 : bool storedMarkerIsRight = toMarker((*insertionIt)->element)->isRightMarker();
557 2 : markerShouldGoBefore = storedMarkerIsRight;
558 : }
559 52 : if (markerShouldGoBefore
560 52 : || ((*insertionIt)->repeatListElementType == RepeatListElementType::JUMP)
561 : ) {
562 : // Decrease position
563 : // This should always be possible as the list always starts with a REPEAT_START element
564 2 : assert(insertionIt != sectionRLElements.begin());
565 2 : --insertionIt;
566 : } else {
567 : // Found location after which we should go
568 50 : break;
569 : }
570 : }
571 : // We should be inserted right after insertionIt
572 273 : sectionRLElements.insert(insertionIt + 1, markerRLE);
573 : }
574 : }
575 : // End
576 14398 : if (m->repeatEnd()) {
577 297 : sectionRLElements.push_back(new RepeatListElement(RepeatListElementType::REPEAT_END, m, m));
578 297 : if (startFromRepeatMeasure != nullptr) {
579 297 : startFromRepeatMeasure->addToRepeatCount(m->repeatCount() - 1);
580 : }
581 297 : if (volta != nullptr) {
582 : //if (volta->endMeasure()->tick() < m->tick()) {
583 : // The previous volta was supposed to end before us (open volta case) -> insert the end
584 120 : sectionRLElements.push_back(new RepeatListElement(RepeatListElementType::VOLTA_END, volta, m));
585 120 : volta = nullptr;
586 : //} else {
587 : // // Volta is spanning over this end repeat, consider splitting the volta
588 : // // or ignoring this repeat all together
589 : //}
590 : }
591 : }
592 : // Volta end
593 28796 : if ((volta != nullptr)
594 218 : && (volta->endMeasure()->tick() == m->tick())
595 14616 : && (volta->getProperty(Pid::END_HOOK_TYPE).value<HookType>() != HookType::NONE)) {
596 : // end of closed volta
597 38 : sectionRLElements.push_back(new RepeatListElement(RepeatListElementType::VOLTA_END, volta, m));
598 38 : volta = nullptr;
599 : }
600 : }
601 : // Section break (or end of score)
602 14470 : if (mb->sectionBreak() || !mb->nextMeasureMM()) {
603 1789 : if (sectionEndMeasureBase != nullptr) {
604 1789 : if (volta != nullptr) {
605 : //if (volta->endMeasure()->tick() < mb->tick()) {
606 : // The previous volta was supposed to end before us (open volta case) -> insert the end
607 42 : sectionRLElements.push_back(new RepeatListElement(RepeatListElementType::VOLTA_END, volta,
608 42 : toMeasure(sectionEndMeasureBase)));
609 42 : volta = nullptr;
610 : //} else {
611 : // // Volta is spanning over this section break, consider splitting the volta
612 : // // and adding it again at the start of the next section
613 : //}
614 : }
615 1789 : sectionRLElements.push_back(new RepeatListElement(RepeatListElementType::SECTION_BREAK, mb,
616 1789 : toMeasure(sectionEndMeasureBase)));
617 1789 : sectionEndMeasureBase = nullptr; // reset to indicate not having found the end for the next section
618 : // store section
619 1789 : m_rlElements.push_back(sectionRLElements);
620 : }
621 : // prepare for new section
622 1789 : if (Measure* nextMeas = mb->nextMeasureMM()) {
623 30 : sectionRLElements = RepeatListElementList();
624 : // First measure of a section/score is always used as a reference REPEAT_START point
625 : // even if it doesn't have a start repeat
626 : startFromRepeatMeasure
627 30 : = new RepeatListElement(RepeatListElementType::REPEAT_START, nextMeas, toMeasure(nextMeas));
628 30 : sectionRLElements.push_back(startFromRepeatMeasure);
629 : } else {
630 : // no more measures -> done
631 1759 : break;
632 : }
633 : }
634 : }
635 1759 : }
636 :
637 : ///
638 : /// \brief Finds a matching marker in the score (section first)
639 : /// \remark Special case labels:
640 : /// "start" will result in start of current section
641 : /// "end" will result in end of current section
642 : ///
643 453 : std::pair<std::vector<RepeatListElementList>::const_iterator, RepeatListElementList::const_iterator> RepeatList::findMarker(
644 : muse::String label, std::vector<RepeatListElementList>::const_iterator referenceSectionIt,
645 : RepeatListElementList::const_iterator referenceRepeatListElementIt) const
646 : {
647 453 : bool found = false;
648 453 : std::vector<RepeatListElementList>::const_iterator foundSectionIt;
649 453 : RepeatListElementList::const_iterator foundRepeatListElementIt;
650 :
651 : // Start in the current section
652 453 : foundSectionIt = referenceSectionIt;
653 : // Handle special label casing first
654 453 : if (label == "start") {
655 77 : foundRepeatListElementIt = referenceSectionIt->cbegin();
656 77 : found = true;
657 376 : } else if (label == "end") {
658 44 : foundRepeatListElementIt = referenceSectionIt->cend() - 1;
659 44 : found = true;
660 : } else {
661 332 : foundRepeatListElementIt = referenceRepeatListElementIt;
662 : }
663 :
664 : // Search backwards in this section
665 1609 : while (!found && (foundRepeatListElementIt != referenceSectionIt->cbegin())) {
666 1156 : --foundRepeatListElementIt;
667 3468 : if (((*foundRepeatListElementIt)->repeatListElementType == RepeatListElementType::MARKER)
668 1156 : && ((toMarker((*foundRepeatListElementIt)->element))->label() == label)
669 : ) {
670 165 : found = true;
671 : }
672 : }
673 :
674 : // Search forwards in this section
675 453 : if (!found) {
676 167 : foundRepeatListElementIt = referenceRepeatListElementIt + 1;
677 553 : while (!found && (foundRepeatListElementIt != referenceSectionIt->cend())) {
678 1401 : if (((*foundRepeatListElementIt)->repeatListElementType == RepeatListElementType::MARKER)
679 467 : && ((toMarker((*foundRepeatListElementIt)->element))->label() == label)
680 : ) {
681 81 : found = true;
682 81 : break;
683 : }
684 386 : ++foundRepeatListElementIt;
685 : }
686 : }
687 :
688 : // Search backwards through all previous sections
689 453 : if (!found) {
690 99 : while (!found && (foundSectionIt != m_rlElements.cbegin())) {
691 13 : --foundSectionIt;
692 13 : foundRepeatListElementIt = foundSectionIt->cend();
693 64 : while (!found && (foundRepeatListElementIt != foundSectionIt->cbegin())) {
694 51 : --foundRepeatListElementIt;
695 153 : if (((*foundRepeatListElementIt)->repeatListElementType == RepeatListElementType::MARKER)
696 51 : && ((toMarker((*foundRepeatListElementIt)->element))->label() == label)
697 : ) {
698 0 : found = true;
699 : }
700 : }
701 : }
702 : }
703 :
704 : // Search forwards through all following sections
705 453 : if (!found) {
706 86 : foundSectionIt = referenceSectionIt + 1;
707 105 : while (foundSectionIt != m_rlElements.cend()) {
708 19 : foundRepeatListElementIt = foundSectionIt->cbegin();
709 102 : while (!found && (foundRepeatListElementIt != foundSectionIt->cend())) {
710 249 : if (((*foundRepeatListElementIt)->repeatListElementType == RepeatListElementType::MARKER)
711 83 : && ((toMarker((*foundRepeatListElementIt)->element))->label() == label)
712 : ) {
713 0 : found = true;
714 0 : break;
715 : }
716 83 : ++foundRepeatListElementIt;
717 : }
718 19 : if (found) {
719 0 : break;
720 : }
721 19 : ++foundSectionIt;
722 : }
723 : }
724 :
725 906 : return std::make_pair(foundSectionIt, foundRepeatListElementIt);
726 : }
727 :
728 : ///
729 : /// \brief RepeatList::performJump
730 : /// \param sectionIt [in] Section of the jump target
731 : /// \param repeatListElementTargetIt [in] RepeatListElement of the jump target within the section
732 : /// \param withRepeats [in] Whether first or last playthrough of the target is the actual target, influences playbackCount
733 : /// \param playbackCount [out] Will contain the resulting playbackCount value
734 : /// \param activeVolta [out] Contains a reference to the active Volta for jump target
735 : /// \param startRepeatReference [out] Reference point to return to and compare against for jump target
736 : ///
737 215 : void RepeatList::performJump(std::vector<RepeatListElementList>::const_iterator sectionIt,
738 : RepeatListElementList::const_iterator repeatListElementTargetIt,
739 : bool withRepeats, int* const playbackCount,
740 : Volta const** const activeVolta, RepeatListElement const** const startRepeatReference) const
741 : {
742 215 : RepeatListElementList::const_iterator repeatListElementIt;
743 : // Fast forward processing up to our desired marker
744 215 : *activeVolta = nullptr;
745 215 : *startRepeatReference = *(sectionIt->cbegin());
746 816 : for (repeatListElementIt = sectionIt->cbegin(); repeatListElementIt != repeatListElementTargetIt; ++repeatListElementIt) {
747 601 : switch ((*repeatListElementIt)->repeatListElementType) {
748 66 : case RepeatListElementType::VOLTA_START: {
749 66 : *activeVolta = toVolta((*repeatListElementIt)->element);
750 66 : } break;
751 61 : case RepeatListElementType::VOLTA_END: {
752 61 : *activeVolta = nullptr;
753 61 : } break;
754 182 : case RepeatListElementType::REPEAT_START: {
755 182 : *startRepeatReference = *repeatListElementIt;
756 182 : } break;
757 292 : default: {
758 : // nothing to do
759 292 : } break;
760 : }
761 : }
762 : // Set the correct playbackCount
763 215 : if (withRepeats) {
764 88 : if (*activeVolta != nullptr) {
765 1 : *playbackCount = (*activeVolta)->firstEnding();
766 1 : if (*playbackCount == 0) {
767 0 : *playbackCount = 1;
768 : }
769 : } else {
770 87 : *playbackCount = 1;
771 : }
772 : } else { // Final repeat after jump
773 127 : if (*activeVolta != nullptr) {
774 4 : *playbackCount = (*activeVolta)->lastEnding();
775 4 : if (*playbackCount == 0) {
776 0 : *playbackCount = (*startRepeatReference)->getRepeatCount();
777 : }
778 : } else {
779 123 : *playbackCount = (*startRepeatReference)->getRepeatCount();
780 : }
781 : }
782 215 : }
783 :
784 : ///
785 : /// \brief RepeatList::unwind
786 : ///
787 1807 : void RepeatList::unwind()
788 : {
789 1821 : TRACEFUNC;
790 :
791 1807 : muse::DeleteAll(*this);
792 1807 : clear();
793 1807 : m_jumpsTaken.clear();
794 :
795 1807 : if (!m_score->firstMeasureMM()) {
796 48 : return;
797 : }
798 :
799 1759 : collectRepeatListElements();
800 :
801 : // Following variables are used during unwinding, but may be altered when following jumps
802 : // Therefor they are declared outside of the loop
803 1759 : RepeatSegment* rs = nullptr;
804 : int playbackCount;
805 1759 : Volta const* activeVolta = nullptr;
806 : std::pair<std::vector<RepeatListElementList>::const_iterator, RepeatListElementList::const_iterator> playUntil
807 1759 : = std::make_pair(m_rlElements.cend(), m_rlElements[0].cend());
808 : std::pair<std::vector<RepeatListElementList>::const_iterator, RepeatListElementList::const_iterator> continueAt
809 1759 : = std::make_pair(m_rlElements.cend(), m_rlElements[0].cend());
810 1759 : Jump const* activeJump = nullptr;
811 1759 : bool forceFinalRepeat = false; // Used during jump processing
812 1759 : RepeatListElementList::const_iterator repeatListElementIt;
813 :
814 3548 : for (std::vector<RepeatListElementList>::const_iterator sectionIt = m_rlElements.cbegin(); sectionIt != m_rlElements.cend();
815 1789 : ++sectionIt) {
816 : // Unwind this section
817 : RepeatListElement const* startRepeatReference;
818 1789 : playbackCount = 1;
819 1789 : repeatListElementIt = sectionIt->cbegin(); // Should always be a REPEAT_START indicator
820 1789 : startRepeatReference = *repeatListElementIt;
821 1789 : activeVolta = nullptr;
822 1789 : playUntil.first = m_rlElements.cend();
823 1789 : continueAt.first = m_rlElements.cend();
824 1789 : forceFinalRepeat = false;
825 :
826 1789 : rs = new RepeatSegment(playbackCount);
827 1789 : rs->addMeasure((*repeatListElementIt)->measure);
828 1789 : ++repeatListElementIt;
829 :
830 5858 : while (repeatListElementIt != sectionIt->cend()) {
831 4069 : if (rs) {
832 3697 : rs->addMeasures((*repeatListElementIt)->measure);
833 : }
834 4069 : switch ((*repeatListElementIt)->repeatListElementType) {
835 1764 : case RepeatListElementType::SECTION_BREAK: {
836 1764 : if ((rs != nullptr) && (!rs->isEmpty())) {
837 1755 : push_back(rs);
838 : }
839 1764 : } break;
840 458 : case RepeatListElementType::VOLTA_START: {
841 458 : activeVolta = toVolta((*repeatListElementIt)->element);
842 458 : if (!(activeVolta->hasEnding(playbackCount))) {
843 : // Should be skipped, remove our measure from rs
844 202 : rs->popMeasure();
845 202 : if (!rs->isEmpty()) {
846 146 : push_back(rs);
847 : }
848 : // Skip the volta
849 : do {
850 372 : ++repeatListElementIt;
851 372 : } while ((*repeatListElementIt)->repeatListElementType != RepeatListElementType::VOLTA_END);
852 202 : activeVolta = nullptr;
853 : // Start next rs on the following measure
854 202 : Measure const* const possibleNextMeasure = (*repeatListElementIt)->measure->nextMeasureMM();
855 202 : if (possibleNextMeasure == nullptr) {
856 9 : rs = nullptr; // end of score, but will still encounter section break, notify it
857 : } else {
858 193 : rs = new RepeatSegment(playbackCount);
859 193 : rs->addMeasure(possibleNextMeasure);
860 : }
861 : }
862 : // else { take the volta, it's already set as activeVolta, so just continue }
863 458 : } break;
864 107 : case RepeatListElementType::VOLTA_END: {
865 107 : activeVolta = nullptr;
866 107 : } break;
867 562 : case RepeatListElementType::REPEAT_START: {
868 562 : if (rs == nullptr) { // Sent here by an end-repeat
869 363 : rs = new RepeatSegment(playbackCount);
870 363 : rs->addMeasure((*repeatListElementIt)->measure);
871 : } else {
872 199 : int desiredPlaybackCount = (forceFinalRepeat) ? (*repeatListElementIt)->getRepeatCount() : 1;
873 199 : if (rs->playbackCount != desiredPlaybackCount) {
874 : // Restart a segment as we have a new playbackCount reference
875 56 : rs->popMeasure();
876 56 : if (!rs->isEmpty()) {
877 54 : push_back(rs);
878 : }
879 56 : playbackCount = desiredPlaybackCount;
880 56 : rs = new RepeatSegment(playbackCount);
881 56 : rs->addMeasure((*repeatListElementIt)->measure);
882 : }
883 199 : startRepeatReference = *repeatListElementIt;
884 : }
885 562 : } break;
886 572 : case RepeatListElementType::REPEAT_END: {
887 572 : (*repeatListElementIt)->addToRepeatCount(1);
888 572 : if ((playbackCount < startRepeatReference->getRepeatCount())
889 572 : && ((*repeatListElementIt)->getRepeatCount() < (*repeatListElementIt)->measure->repeatCount())
890 : ) {
891 : // Honor the repeat
892 363 : if ((rs != nullptr) && (!rs->isEmpty())) {
893 363 : push_back(rs);
894 : }
895 363 : rs = nullptr;
896 : do { // rewind
897 811 : --repeatListElementIt;
898 811 : if ((*repeatListElementIt)->repeatListElementType == RepeatListElementType::VOLTA_START) {
899 230 : activeVolta = nullptr;
900 581 : } else if ((*repeatListElementIt)->repeatListElementType == RepeatListElementType::VOLTA_END) {
901 101 : activeVolta = toVolta((*repeatListElementIt)->element);
902 : }
903 811 : } while ((*repeatListElementIt) != startRepeatReference);
904 363 : ++playbackCount;
905 363 : continue; // Force evaluation of the start repeat
906 : }
907 : //else { // Exhausted repeats, just continue }
908 209 : } break;
909 229 : case RepeatListElementType::JUMP: {
910 229 : if (activeJump == toJump((*repeatListElementIt)->element)) {
911 : // We've reached this jump again after just having taken it
912 : // If this jump forced final repeat playthrough of measures
913 : // it only forces so up to this point - see test::repeat23
914 57 : forceFinalRepeat = false;
915 : }
916 : // TODO future improvement, use the repeatList property from the Jump to verify if it should be honored
917 : // For now (or in case of an empty repeatList property) a Jump is only honored on final playthrough
918 : // of the measure, and only taken once
919 229 : if ((playbackCount >= startRepeatReference->getRepeatCount())
920 229 : || ((activeVolta != nullptr) && (playbackCount == activeVolta->lastEnding()))
921 : ) {
922 : std::pair<Jump const* const,
923 213 : int> jumpOccurrence = std::make_pair(toJump((*repeatListElementIt)->element), playbackCount);
924 213 : if (m_jumpsTaken.find(jumpOccurrence) == m_jumpsTaken.end()) { // Not yet processed
925 : // Processing it now
926 151 : m_jumpsTaken.insert(jumpOccurrence);
927 : // Find the jump targets
928 : std::pair<std::vector<RepeatListElementList>::const_iterator,
929 151 : RepeatListElementList::const_iterator> jumpTo = findMarker(
930 302 : jumpOccurrence.first->jumpTo(), sectionIt, repeatListElementIt);
931 151 : playUntil = findMarker(jumpOccurrence.first->playUntil(), sectionIt, repeatListElementIt);
932 151 : continueAt = findMarker(jumpOccurrence.first->continueAt(), sectionIt, repeatListElementIt);
933 :
934 : // Execute
935 151 : if (jumpTo.first != m_rlElements.cend()) {
936 147 : if (rs && !rs->isEmpty()) {
937 147 : push_back(rs);
938 : }
939 147 : rs = nullptr;
940 :
941 147 : activeJump = jumpOccurrence.first;
942 147 : performJump(jumpTo.first, jumpTo.second,
943 147 : activeJump->playRepeats(), &playbackCount, &activeVolta, &startRepeatReference);
944 147 : sectionIt = jumpTo.first;
945 147 : repeatListElementIt = jumpTo.second;
946 147 : forceFinalRepeat = !(activeJump->playRepeats());
947 :
948 : // Re-evaluate our repeat count for end repeat measures
949 147 : if (playUntil.first != m_rlElements.cend()) { // Only required if we have an end target
950 1108 : for (auto rleIt = repeatListElementIt + 1; rleIt != sectionIt->cend(); ++rleIt) {
951 969 : if (((*rleIt)->repeatListElementType == RepeatListElementType::REPEAT_END)
952 969 : && ((*rleIt)->getRepeatCount() != 0)
953 : ) { // We've been played before - see test::repeat22 for why only then
954 : // Clear out our current repeat count
955 75 : (*rleIt)->addToRepeatCount(-((*rleIt)->getRepeatCount()));
956 75 : if (forceFinalRepeat) {
957 : // Set repeat count to the maximum number for this repeat
958 57 : (*rleIt)->addToRepeatCount((*rleIt)->measure->repeatCount());
959 : }
960 : }
961 : }
962 : }
963 147 : if (activeVolta != nullptr) {
964 : // We jumped into a volta, which might not be the only one of this startRepeatReference
965 : // If our jump didn't take us to the last playthrough, we must re-evaluate
966 : // all voltas related to this startRepeatReference
967 5 : if (playbackCount < startRepeatReference->getRepeatCount()) {
968 : // test::repeat52 and test::repeat53
969 3 : RepeatListElementList::const_iterator findRepeatIt = repeatListElementIt;
970 : do {
971 9 : --findRepeatIt;
972 9 : } while ((*findRepeatIt) != startRepeatReference);
973 3 : ++findRepeatIt; // Start volta analysis past this start repeat
974 3 : Volta const* voltaReference = nullptr;
975 3 : int processedRepeatCount = 1;
976 18 : while ((findRepeatIt != sectionIt->cend())
977 18 : && ((*findRepeatIt)->repeatListElementType != RepeatListElementType::REPEAT_START)
978 36 : && (processedRepeatCount < startRepeatReference->getRepeatCount())
979 : ) {
980 15 : if ((*findRepeatIt)->repeatListElementType == RepeatListElementType::VOLTA_START) {
981 5 : voltaReference = toVolta((*findRepeatIt)->element);
982 5 : if (voltaReference->lastEnding() < playbackCount) {
983 : // We won't pass here anymore - no need to adjust end repeat to this volta
984 0 : voltaReference = nullptr;
985 : }
986 10 : } else if ((*findRepeatIt)->repeatListElementType == RepeatListElementType::REPEAT_END) {
987 5 : if (voltaReference != nullptr) {
988 5 : int remainingRepeatsCount = 0;
989 14 : for (int ending : voltaReference->endings()) {
990 9 : if (ending >= playbackCount) {
991 6 : ++remainingRepeatsCount;
992 : }
993 5 : }
994 : // Apply new remainingRepeatsCount
995 5 : (*findRepeatIt)->addToRepeatCount(-((*findRepeatIt)->getRepeatCount()));
996 5 : (*findRepeatIt)->addToRepeatCount(
997 5 : (*findRepeatIt)->measure->repeatCount() - remainingRepeatsCount - 1);
998 : }
999 5 : processedRepeatCount += (*findRepeatIt)->measure->repeatCount() - 1;
1000 : }
1001 15 : ++findRepeatIt;
1002 : }
1003 : }
1004 : }
1005 :
1006 : // We've arrived at the target marker
1007 147 : rs = new RepeatSegment(playbackCount);
1008 147 : rs->addMeasure((*repeatListElementIt)->measure);
1009 : } // End of jump execution
1010 : }
1011 : }
1012 229 : } break;
1013 377 : case RepeatListElementType::MARKER: {
1014 524 : if (((sectionIt == playUntil.first) && (repeatListElementIt == playUntil.second))
1015 525 : && ((playbackCount == startRepeatReference->getRepeatCount())
1016 1 : || ((activeVolta != nullptr) && (playbackCount == activeVolta->lastEnding()))
1017 : )
1018 : ) {
1019 : // Found final playThrough of this Marker
1020 93 : if (rs && !rs->isEmpty()) {
1021 93 : push_back(rs);
1022 : }
1023 93 : rs = nullptr;
1024 93 : playUntil.first = m_rlElements.cend(); // Clear this reference - processed
1025 93 : forceFinalRepeat = false;
1026 :
1027 93 : if (continueAt.first != m_rlElements.cend()) {
1028 68 : performJump(continueAt.first, continueAt.second, true, &playbackCount, &activeVolta, &startRepeatReference);
1029 68 : sectionIt = continueAt.first;
1030 68 : repeatListElementIt = continueAt.second;
1031 68 : if (startRepeatReference->measure != (*(continueAt.second))->measure) {
1032 : // Use the continueAt target as repeat reference if it wasn't this measure already
1033 : // Check for measure is required as REPEAT_START is processed before a marker
1034 : // see test::repeat23 m12
1035 67 : startRepeatReference = *(continueAt.second);
1036 : }
1037 :
1038 : // We've arrived at the target marker
1039 68 : rs = new RepeatSegment(playbackCount);
1040 68 : rs->addMeasure((*repeatListElementIt)->measure);
1041 :
1042 68 : continueAt.first = m_rlElements.cend(); // Clear this reference - processed
1043 : } else { // Nowhere to go to, break out of this section loop and onto the next section
1044 25 : repeatListElementIt = sectionIt->cend();
1045 25 : continue;
1046 : }
1047 : }
1048 352 : } break;
1049 : }
1050 3681 : ++repeatListElementIt;
1051 : }
1052 :
1053 : // Reached the end of this section
1054 1789 : if (!this->empty()) {
1055 : // Inform the last RepeatSegment that the Section Break pause property should be honored now
1056 1788 : rs = this->back();
1057 1788 : repeatListElementIt = sectionIt->cend() - 1;
1058 1788 : assert((*repeatListElementIt)->repeatListElementType == RepeatListElementType::SECTION_BREAK);
1059 :
1060 1788 : LayoutBreak const* const layoutBreak = toMeasureBase((*repeatListElementIt)->element)->sectionBreakElement();
1061 1788 : if (layoutBreak != nullptr) {
1062 31 : rs->pause = layoutBreak->pause();
1063 : }
1064 : }
1065 : }
1066 :
1067 1759 : updateUticks();
1068 1759 : m_expanded = true;
1069 1807 : }
1070 : }
|