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 : /**
24 : File handling: loading and saving.
25 : */
26 :
27 : #include "style/style.h"
28 : #include "../editing/editexcerpt.h"
29 : #include "../editing/transaction/transaction.h"
30 :
31 : #include "barline.h"
32 : #include "engravingitem.h"
33 : #include "excerpt.h"
34 : #include "masterscore.h"
35 : #include "measure.h"
36 : #include "measurebase.h"
37 : #include "part.h"
38 : #include "repeatlist.h"
39 : #include "score.h"
40 : #include "segment.h"
41 :
42 : #include "log.h"
43 :
44 : namespace mu::engraving {
45 0 : static void removeRepeatMarkings(Score* score)
46 : {
47 : // remove bar-level repeats
48 0 : for (Measure* m = score->firstMeasure(); m; m = m->nextMeasure()) {
49 0 : m->setRepeatStart(false);
50 0 : m->setRepeatEnd(false);
51 : }
52 :
53 : // remove volta markers
54 0 : auto smap = score->spannerMap().map();
55 0 : for (auto it = smap.cbegin(); it != smap.cend(); ++it) {
56 0 : Spanner* s = (*it).second;
57 0 : if (!s || !s->isVolta()) {
58 0 : continue;
59 : }
60 0 : score->removeSpanner(s);
61 : }
62 :
63 : // remove coda/fine labels and jumps
64 0 : std::vector<EngravingItem*> elems = score->getChildren(false);
65 0 : for (auto e : elems) {
66 0 : if (e->isMarker() || e->isJump()) {
67 0 : score->deleteItem(e);
68 0 : } else if (e->isBarLine()) {
69 0 : toBarLine(e)->setBarLineType(BarLineType::NORMAL);
70 : }
71 : }
72 :
73 : // set the last bar line to end symbol
74 0 : score->lastMeasure()->setEndBarLineType(BarLineType::END, false);
75 0 : Segment* last = score->lastMeasure()->segments().last();
76 0 : if (last->segmentType() == SegmentType::EndBarLine) {
77 0 : auto els = last->elist();
78 0 : for (size_t i = 0; i < els.size(); i++) {
79 0 : if (!els[i]) {
80 0 : continue;
81 : }
82 0 : toBarLine(els[i])->setBarLineType(BarLineType::END);
83 : }
84 0 : }
85 0 : }
86 :
87 : //---------------------------------------------------------
88 : // createExcerpts
89 : // re-create all the excerpts once the master score
90 : // has been unrolled
91 : //---------------------------------------------------------
92 :
93 0 : static void createExcerpts(MasterScore* cs, const std::vector<Excerpt*>& excerpts)
94 : {
95 : // borrowed from musescore.cpp endsWith(".pdf")
96 0 : for (Excerpt* e : excerpts) {
97 0 : Score* nscore = e->masterScore()->createScore();
98 0 : e->setExcerptScore(nscore);
99 0 : nscore->style().set(Sid::createMultiMeasureRests, true);
100 0 : cs->transactionManager()->transaction(TranslatableString("undoableAction", "Create parts"), [&](auto& tx) {
101 0 : tx.push(new AddExcerpt(e));
102 0 : Excerpt::createExcerpt(e);
103 :
104 : // borrowed from excerptsdialog.cpp
105 : // a new excerpt is created in AddExcerpt, make sure the parts are filed
106 0 : for (Excerpt* ee : e->masterScore()->excerpts()) {
107 0 : if (ee->excerptScore() == nscore && ee != e) {
108 0 : ee->parts().clear();
109 0 : ee->parts().insert(ee->parts().end(), e->parts().begin(), e->parts().end());
110 : }
111 : }
112 0 : });
113 : }
114 0 : }
115 :
116 : //---------------------------------------------------------
117 : // unrollRepeats
118 : // unroll all the repeats
119 : //---------------------------------------------------------
120 :
121 0 : MasterScore* MasterScore::unrollRepeats()
122 : {
123 0 : MasterScore* original = this;
124 :
125 : // create a copy of the original score to play with
126 0 : MasterScore* score = original->clone();
127 :
128 : // if no repeats, just return the score as-is
129 0 : const RepeatList& expandedRepeats = original->expandedRepeatList();
130 0 : if (expandedRepeats.size() == 1) {
131 0 : return score;
132 : }
133 :
134 : // remove excerpts for now (they are re-created after unrolling master score)
135 0 : std::vector<Excerpt*> excerpts;
136 0 : excerpts.reserve(score->excerpts().size());
137 0 : for (Excerpt* e : score->excerpts()) {
138 0 : excerpts.push_back(new Excerpt(*e, false));
139 0 : score->masterScore()->deleteExcerpt(e);
140 : }
141 :
142 : // follow along with the repeatList
143 0 : bool first = true;
144 0 : for (const RepeatSegment* rs: expandedRepeats) {
145 0 : Fraction startTick = Fraction::fromTicks(rs->tick);
146 0 : Fraction endTick = Fraction::fromTicks(rs->endTick());
147 :
148 : // first segment left from clone, everything past that removed
149 0 : if (first) {
150 0 : if (endTick <= score->lastMeasure()->tick()) { // check if we actually need to remove any measures
151 0 : score->deleteMeasures(score->tick2measure(endTick), score->lastMeasure());
152 : }
153 0 : first = false;
154 : } else { // just append this section from the original to the new score
155 0 : score->appendMeasuresFromScore(original, startTick, endTick);
156 : }
157 : }
158 :
159 0 : removeRepeatMarkings(score);
160 :
161 0 : score->updateTicksAndTimeSigMap();
162 :
163 0 : score->setLayoutAll();
164 0 : score->doLayout();
165 :
166 : // re-create excerpt parts
167 0 : if (!excerpts.empty()) {
168 0 : createExcerpts(score, excerpts);
169 : }
170 :
171 0 : return score;
172 0 : }
173 : }
|