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) 2023 MuseScore Limited and others
9 : *
10 : * This program is free software: you can redistribute it and/or modify
11 : * it under the terms of the GNU General Public License version 3 as
12 : * published by the Free Software Foundation.
13 : *
14 : * This program is distributed in the hope that it will be useful,
15 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : * GNU General Public License for more details.
18 : *
19 : * You should have received a copy of the GNU General Public License
20 : * along with this program. If not, see <https://www.gnu.org/licenses/>.
21 : */
22 : #include "modifydom.h"
23 :
24 : #include "dom/measure.h"
25 : #include "dom/staff.h"
26 : #include "dom/spannermap.h"
27 : #include "dom/timesig.h"
28 : #include "dom/trill.h"
29 : #include "dom/ornament.h"
30 : #include "dom/note.h"
31 : #include "dom/utils.h"
32 : #include "dom/chord.h"
33 : #include "dom/keysig.h"
34 : #include "dom/hook.h"
35 : #include "dom/part.h"
36 : #include "dom/score.h"
37 : #include "editing/addremoveelement.h"
38 : #include "rendering/score/chordlayout.h"
39 :
40 : using namespace mu::engraving::rendering::score;
41 :
42 30347 : void ModifyDom::setCrossMeasure(const Measure* measure, LayoutContext& ctx)
43 : {
44 30347 : bool crossMeasure = ctx.conf().styleB(Sid::crossMeasureValues);
45 30347 : const DomAccessor& dom = ctx.dom();
46 74673 : for (staff_idx_t staffIdx = 0; staffIdx < dom.nstaves(); ++staffIdx) {
47 44326 : const Staff* staff = dom.staff(staffIdx);
48 44326 : if (!staff->show()) {
49 667 : continue;
50 : }
51 :
52 43659 : track_idx_t startTrack = staffIdx * VOICES;
53 43659 : track_idx_t endTrack = startTrack + VOICES;
54 :
55 178072 : for (const Segment& segment : measure->segments()) {
56 134413 : if (!segment.isJustType(SegmentType::ChordRest)) {
57 46567 : continue;
58 : }
59 :
60 439230 : for (track_idx_t t = startTrack; t < endTrack; ++t) {
61 351384 : ChordRest* cr = segment.cr(t);
62 351384 : if (!cr) {
63 264283 : continue;
64 : }
65 87101 : if (cr->isChord()) {
66 48116 : Chord* chord = toChord(cr);
67 48116 : if (!chord->isGrace()) {
68 48116 : ChordLayout::crossMeasureSetup(chord, crossMeasure, ctx);
69 : }
70 : }
71 : }
72 : }
73 : }
74 30347 : }
75 :
76 30347 : void ModifyDom::connectTremolo(Measure* m)
77 : {
78 30347 : m->connectTremolo();
79 30347 : }
80 :
81 30347 : void ModifyDom::cmdUpdateNotes(const Measure* measure, const DomAccessor& dom)
82 : {
83 74673 : for (staff_idx_t staffIdx = 0; staffIdx < dom.nstaves(); ++staffIdx) {
84 44326 : const Staff* staff = dom.staff(staffIdx);
85 44326 : if (!staff->show()) {
86 667 : continue;
87 : }
88 :
89 43659 : AccidentalState as; // list of already set accidentals for this measure
90 : // initAccidentalState
91 : {
92 43659 : as.init(staff->keySigEvent(measure->tick()));
93 :
94 : // Trills may carry an accidental into this measure that requires a force-restate
95 43659 : int ticks = measure->tick().ticks();
96 43659 : auto spanners = dom.spannerMap().findOverlapping(ticks, ticks, true);
97 47400 : for (auto iter : spanners) {
98 3741 : Spanner* spanner = iter.value;
99 5947 : if (spanner->staffIdx() != staffIdx || !spanner->isTrill()
100 5947 : || spanner->tick() == measure->tick() || spanner->tick2() == measure->tick()) {
101 3726 : continue;
102 : }
103 15 : Ornament* ornament = toTrill(spanner)->ornament();
104 15 : Note* trillNote = ornament ? ornament->noteAbove() : nullptr;
105 15 : if (trillNote && trillNote->accidental() && ornament->showAccidental() == OrnamentShowAccidental::DEFAULT) {
106 6 : int line = absStep(trillNote->tpc(), trillNote->epitch());
107 6 : as.setForceRestateAccidental(line, true);
108 : }
109 : }
110 43659 : }
111 :
112 43659 : const TrackRange trackRange = staff->part()->trackRange();
113 43659 : track_idx_t mainTrack = staffIdx * VOICES;
114 :
115 178072 : for (const Segment& segment : measure->segments()) {
116 134413 : if (segment.isJustType(SegmentType::KeySig)) {
117 6699 : KeySig* ks = item_cast<KeySig*>(segment.element(mainTrack));
118 6699 : if (ks) {
119 6443 : Fraction tick = segment.tick();
120 6443 : as.init(staff->keySigEvent(tick));
121 : }
122 127714 : } else if (segment.isJustType(SegmentType::ChordRest)) {
123 533850 : for (track_idx_t t = trackRange.startTrack; t < trackRange.endTrack; ++t) {
124 446004 : Chord* chord = item_cast<Chord*>(segment.element(t), CastMode::MAYBE_BAD); // maybe Rest
125 446004 : if (chord) {
126 59965 : chord->cmdUpdateNotes(&as, staffIdx);
127 : }
128 : }
129 : }
130 : }
131 : }
132 30347 : }
133 :
134 30347 : void ModifyDom::createStems(const Measure* measure, LayoutContext& ctx)
135 : {
136 30347 : const DomAccessor& dom = ctx.dom();
137 74673 : for (staff_idx_t staffIdx = 0; staffIdx < dom.nstaves(); ++staffIdx) {
138 44326 : const Staff* staff = dom.staff(staffIdx);
139 44326 : if (!staff->show()) {
140 667 : continue;
141 : }
142 :
143 43659 : track_idx_t startTrack = staffIdx * VOICES;
144 43659 : track_idx_t endTrack = startTrack + VOICES;
145 :
146 178072 : for (const Segment& segment : measure->segments()) {
147 134413 : if (!segment.isJustType(SegmentType::ChordRest)) {
148 46567 : continue;
149 : }
150 :
151 439230 : for (track_idx_t t = startTrack; t < endTrack; ++t) {
152 351384 : ChordRest* cr = segment.cr(t);
153 351384 : if (!cr) {
154 264283 : continue;
155 : }
156 :
157 49021 : auto createStems = [](Chord* chord) {
158 49021 : if (!chord->shouldHaveStem()) {
159 5203 : chord->removeStem();
160 5203 : return;
161 : }
162 :
163 43818 : if (!chord->stem()) {
164 22727 : chord->createStem();
165 : }
166 : };
167 :
168 87101 : if (cr->isChord()) {
169 48116 : Chord* chord = toChord(cr);
170 :
171 49021 : for (Chord* c : chord->graceNotes()) {
172 905 : createStems(c);
173 : }
174 :
175 48116 : createStems(chord); // create stems needed to calculate spacing
176 : // stem direction can change later during beam processing
177 : }
178 : }
179 : }
180 : }
181 30347 : }
182 :
183 30347 : void ModifyDom::setTrackForChordGraceNotes(Measure* measure, const DomAccessor& dom)
184 : {
185 74673 : for (staff_idx_t staffIdx = 0; staffIdx < dom.nstaves(); ++staffIdx) {
186 44326 : track_idx_t startTrack = staffIdx * VOICES;
187 44326 : track_idx_t endTrack = startTrack + VOICES;
188 :
189 180656 : for (const Segment& segment : measure->segments()) {
190 136330 : if (!segment.isJustType(SegmentType::ChordRest)) {
191 47636 : continue;
192 : }
193 :
194 443470 : for (track_idx_t t = startTrack; t < endTrack; ++t) {
195 354776 : ChordRest* cr = segment.cr(t);
196 354776 : if (!cr) {
197 266871 : continue;
198 : }
199 :
200 87905 : if (cr->isChord()) {
201 48252 : Chord* chord = toChord(cr);
202 49158 : for (Chord* c : chord->graceNotes()) {
203 906 : c->setTrack(t);
204 : }
205 : }
206 : }
207 : }
208 : }
209 30347 : }
210 :
211 30347 : void ModifyDom::sortMeasureSegments(Measure* measure, LayoutContext& ctx)
212 : {
213 30347 : measure = measure->coveringMMRestOrThis();
214 :
215 : // Move segments between measure which need to move
216 :
217 : // Move key and time signature segments to the correct measure.
218 : // Depending on configuration, this could mean moving segments at the end of this measure to the start of the following measure
219 : // or moving segments from the start of the following measure to the end of this measure
220 :
221 : // Loop through clef, key, time sigs in this bar. If any are found and shouldn't be in this bar, move to the next
222 :
223 19 : auto changeAppliesToRepeatAndContinuation = [&](const Segment& seg) -> bool {
224 : // Check if the change applies to the beginning of the repeat section as well as the continuation
225 19 : const std::vector<Measure*> measures = findFollowingRepeatMeasures(measure);
226 25 : for (const Measure* repeatMeasure : measures) {
227 22 : if (repeatMeasure == measure->nextMeasureMM()) {
228 3 : continue;
229 : }
230 19 : const Fraction startTick = repeatMeasure->tick();
231 22 : for (track_idx_t track = 0; track < ctx.dom().nstaves(); track += VOICES) {
232 19 : const Staff* staff = ctx.dom().staff(track2staff(track));
233 :
234 19 : if (seg.isKeySigType()) {
235 3 : const Key continuationKey = staff->key(seg.tick());
236 3 : const Key repeatKey = staff->key(startTick);
237 3 : const Key keyBeforeContinuation = staff->key(seg.tick() - Fraction::eps());
238 16 : return keyBeforeContinuation != continuationKey && continuationKey == repeatKey;
239 : }
240 :
241 16 : if (seg.isTimeSigType()) {
242 13 : const TimeSig* continuationTimeSig = staff->timeSig(seg.tick());
243 13 : const TimeSig* repeatTimeSig = staff->timeSig(startTick);
244 13 : const TimeSig* timeSigBeforeContinuation = staff->timeSig(seg.tick() - Fraction::eps());
245 13 : return continuationTimeSig && repeatTimeSig && timeSigBeforeContinuation
246 13 : && timeSigBeforeContinuation->sig() != continuationTimeSig->sig()
247 26 : && continuationTimeSig->sig() == repeatTimeSig->sig();
248 : }
249 :
250 3 : if (seg.isClefType()) {
251 3 : const ClefType continuationClef = staff->clef(seg.tick());
252 3 : const ClefType repeatClef = staff->clef(startTick);
253 3 : const ClefType clefBeforeContinuation = staff->clef(seg.tick() - Fraction::eps());
254 3 : if (clefBeforeContinuation != continuationClef && continuationClef == repeatClef) {
255 0 : return true;
256 : }
257 : }
258 : }
259 : }
260 3 : return false;
261 19 : };
262 :
263 228 : auto clefSegBarlinePosition = [&](const Segment& seg) -> ClefToBarlinePosition
264 : {
265 1476 : for (EngravingItem* el : seg.elist()) {
266 1253 : if (!el || !el->isClef()) {
267 1018 : continue;
268 : }
269 235 : const Clef* clef = toClef(el);
270 235 : if (clef->clefToBarlinePosition() != ClefToBarlinePosition::AUTO) {
271 5 : return clef->clefToBarlinePosition();
272 : }
273 : }
274 223 : return ClefToBarlinePosition::AUTO;
275 : };
276 :
277 30347 : MeasureBase* nextMb = measure ? measure->nextMM() : nullptr;
278 :
279 30347 : if (!nextMb || !nextMb->isMeasure()) {
280 3930 : return;
281 : }
282 :
283 26417 : Measure* nextMeasure = toMeasure(nextMb);
284 :
285 26739 : const bool sigsShouldBeInThisMeasure = ((measure->repeatEnd() && ctx.conf().styleB(Sid::changesBeforeBarlineRepeats))
286 26739 : || (measure->repeatJump() && ctx.conf().styleB(Sid::changesBeforeBarlineOtherJumps)));
287 26417 : std::vector<Segment*> segsToRemove;
288 :
289 26417 : std::vector<Segment*> segsToMoveToNextMeasure;
290 104555 : for (Segment& seg : measure->segments()) {
291 78138 : if (seg.tick() != measure->endTick() || seg.isChordRestType()) {
292 64087 : continue;
293 : }
294 :
295 : // Move clefs at the end of this measure into the next measure
296 14051 : if (seg.isClefType()) {
297 217 : ClefToBarlinePosition pos = clefSegBarlinePosition(seg);
298 : // Clef position explicitly set by user
299 217 : if (pos == ClefToBarlinePosition::BEFORE) {
300 0 : continue;
301 217 : } else if (pos == ClefToBarlinePosition::AFTER) {
302 0 : segsToMoveToNextMeasure.push_back(&seg);
303 0 : continue;
304 : }
305 :
306 : // AUTO on normal barline
307 217 : if (!measure->repeatEnd()) {
308 217 : continue;
309 : }
310 :
311 : // Otherwise, pos is AUTO
312 : // Place changes before barline & clefs before repeats style settings
313 0 : if ((!sigsShouldBeInThisMeasure && !changeAppliesToRepeatAndContinuation(seg))
314 0 : || (measure->repeatEnd() && !ctx.conf().styleB(Sid::placeClefsBeforeRepeats))) {
315 0 : segsToMoveToNextMeasure.push_back(&seg);
316 0 : continue;
317 : }
318 : }
319 :
320 : // Move key sigs and time sigs at the end of this measure into the next measure
321 27668 : if ((seg.isKeySigType() || seg.isTimeSigType()) && !seg.header() && !seg.trailer()
322 27668 : && (!sigsShouldBeInThisMeasure || !changeAppliesToRepeatAndContinuation(seg))) {
323 0 : if (nextMeasure && nextMeasure->findSegmentR(seg.segmentType(), Fraction(0, 1))) {
324 0 : segsToRemove.push_back(&seg);
325 0 : continue;
326 : }
327 0 : segsToMoveToNextMeasure.push_back(&seg);
328 : }
329 : }
330 :
331 : // No next measure, so these segments are useless
332 26417 : if (!nextMeasure) {
333 0 : for (Segment* seg : segsToMoveToNextMeasure) {
334 0 : ctx.mutDom().doUndoRemoveElement(seg);
335 : }
336 0 : return;
337 : }
338 :
339 26417 : std::vector<Segment*> segsToMoveToThisMeasure;
340 95454 : for (Segment& seg : nextMeasure->segments()) {
341 69037 : if (seg.tick() != nextMeasure->tick() || seg.isChordRestType()) {
342 64718 : continue;
343 : }
344 :
345 : // Move clefs at the beginning of the next measure into this measure
346 4319 : if (seg.isClefType()) {
347 11 : ClefToBarlinePosition pos = clefSegBarlinePosition(seg);
348 : // Clef position explicitly set by user
349 11 : if (pos == ClefToBarlinePosition::BEFORE) {
350 0 : segsToMoveToThisMeasure.push_back(&seg);
351 0 : continue;
352 11 : } else if (pos == ClefToBarlinePosition::AFTER) {
353 5 : continue;
354 : }
355 :
356 6 : if (!measure->repeatEnd()) {
357 3 : segsToMoveToThisMeasure.push_back(&seg);
358 3 : continue;
359 : }
360 :
361 : // Otherwise, pos is AUTO
362 : // Place changes before barline & clefs before repeats style settings
363 3 : if ((sigsShouldBeInThisMeasure && changeAppliesToRepeatAndContinuation(seg))
364 6 : || !measure->repeatEnd() || ctx.conf().styleB(Sid::placeClefsBeforeRepeats)) {
365 1 : segsToMoveToThisMeasure.push_back(&seg);
366 : }
367 : }
368 :
369 : // Move key sigs and time sigs at the start of the next measure to the end of this measure
370 8622 : if ((seg.isTimeSigType() || seg.isKeySigType()) && !seg.header() && !seg.trailer()
371 8622 : && sigsShouldBeInThisMeasure && changeAppliesToRepeatAndContinuation(seg)) {
372 3 : if (measure->findSegmentR(seg.segmentType(), measure->ticks())) {
373 0 : segsToRemove.push_back(&seg);
374 0 : continue;
375 : }
376 3 : segsToMoveToThisMeasure.push_back(&seg);
377 : }
378 : }
379 :
380 26417 : for (Segment* seg : segsToRemove) {
381 : // Don't add duplicate segs to a measure
382 0 : ctx.mutDom().doUndoRemoveElement(seg);
383 :
384 : // Remove from underlying measures
385 0 : Measure* segMeasure = seg->measure();
386 0 : if (segMeasure && segMeasure->isMMRest()) {
387 0 : Measure* target = nullptr;
388 : // Segments at the start of the measure -> mmRestFirst, end -> mmRestLast
389 0 : if (seg->rtick() == Fraction(0, 1) || seg->tick() == segMeasure->tick()) {
390 0 : target = segMeasure->mmRestFirst();
391 : } else {
392 0 : target = segMeasure->mmRestLast();
393 : }
394 0 : if (target && target != segMeasure) {
395 0 : Segment* counterpart = target->findSegmentR(seg->segmentType(), seg->rtick());
396 0 : if (counterpart) {
397 0 : ctx.mutDom().doUndoRemoveElement(counterpart);
398 : }
399 : }
400 : }
401 : }
402 :
403 26417 : for (Segment* seg : segsToMoveToNextMeasure) {
404 0 : Fraction origRtick = seg->rtick();
405 :
406 0 : seg->undoChangeProperty(Pid::END_OF_MEASURE_CHANGE, false);
407 0 : measure->score()->undo(new ChangeSegmentParent(seg, nextMeasure, Fraction(0, 1)));
408 :
409 : // Move in underlying segments
410 0 : if (measure->isMMRest()) {
411 0 : Measure* fromMmLast = measure->mmRestLast();
412 0 : if (fromMmLast) {
413 0 : Segment* underlyingSeg = fromMmLast->findSegmentR(seg->segmentType(), origRtick);
414 0 : if (underlyingSeg) {
415 0 : underlyingSeg->undoChangeProperty(Pid::END_OF_MEASURE_CHANGE, false);
416 0 : if (nextMeasure->isMMRest() && nextMeasure->mmRestFirst()) {
417 0 : nextMeasure->score()->undo(new ChangeSegmentParent(underlyingSeg, nextMeasure->mmRestFirst(), Fraction(0, 1)));
418 : } else {
419 0 : ctx.mutDom().doUndoRemoveElement(underlyingSeg);
420 : }
421 : }
422 : }
423 : }
424 :
425 : // If the destination is an MMRest but the source is not, create underlying segment
426 0 : if (nextMeasure->isMMRest() && !measure->isMMRest()) {
427 0 : Measure* mmFirst = nextMeasure->mmRestFirst();
428 0 : if (mmFirst && mmFirst != nextMeasure) {
429 0 : Segment* mmSeg = mmFirst->undoGetSegmentR(seg->segmentType(), Fraction(0, 1));
430 0 : mmSeg->undoChangeProperty(Pid::END_OF_MEASURE_CHANGE, false);
431 0 : for (track_idx_t track = 0; track < ctx.dom().ntracks(); track += VOICES) {
432 0 : EngravingItem* e = seg->element(track);
433 0 : if (!e) {
434 0 : continue;
435 : }
436 0 : if (!mmSeg->element(track)) {
437 0 : bool generated = e->generated();
438 0 : EngravingItem* eClone = generated ? e->clone() : e->linkedClone();
439 0 : eClone->setGenerated(generated);
440 0 : eClone->setOwnershipParent(mmSeg);
441 0 : ctx.mutDom().doUndoAddElement(eClone);
442 : }
443 : }
444 : }
445 : }
446 : }
447 :
448 26424 : for (Segment* seg : segsToMoveToThisMeasure) {
449 7 : Fraction origRtick = seg->rtick();
450 :
451 7 : seg->undoChangeProperty(Pid::END_OF_MEASURE_CHANGE, true);
452 7 : measure->score()->undo(new ChangeSegmentParent(seg, measure, measure->ticks()));
453 :
454 : // Move in underlying segments
455 7 : if (nextMeasure->isMMRest()) {
456 1 : Measure* fromMmFirst = nextMeasure->mmRestFirst();
457 1 : if (fromMmFirst) {
458 1 : Segment* underlyingSeg = fromMmFirst->findSegmentR(seg->segmentType(), origRtick);
459 1 : if (underlyingSeg) {
460 1 : underlyingSeg->undoChangeProperty(Pid::END_OF_MEASURE_CHANGE, true);
461 1 : if (measure->isMMRest() && measure->mmRestLast()) {
462 2 : measure->score()->undo(new ChangeSegmentParent(underlyingSeg, measure->mmRestLast(),
463 1 : measure->mmRestLast()->ticks()));
464 : } else {
465 0 : ctx.mutDom().doUndoRemoveElement(underlyingSeg);
466 : }
467 : }
468 : }
469 : }
470 :
471 : // If the destination is an MMRest but the source is not, create underlying segment
472 7 : if (measure->isMMRest() && !nextMeasure->isMMRest()) {
473 1 : Measure* mmLast = measure->mmRestLast();
474 1 : if (mmLast && mmLast != measure) {
475 1 : Segment* mmSeg = mmLast->undoGetSegmentR(seg->segmentType(), measure->ticks());
476 1 : mmSeg->undoChangeProperty(Pid::END_OF_MEASURE_CHANGE, true);
477 : // Clone per-track elements from the moved segment into the underlying mmrest segment
478 2 : for (track_idx_t track = 0; track < ctx.dom().ntracks(); track += VOICES) {
479 1 : EngravingItem* e = seg->element(track);
480 1 : if (!e) {
481 0 : continue;
482 : }
483 1 : if (!mmSeg->element(track)) {
484 1 : bool generated = e->generated();
485 1 : EngravingItem* eClone = generated ? e->clone() : e->linkedClone();
486 1 : eClone->setGenerated(generated);
487 1 : eClone->setOwnershipParent(mmSeg);
488 1 : ctx.mutDom().doUndoAddElement(eClone);
489 : }
490 : }
491 : }
492 : }
493 : }
494 :
495 : // Check end of measure changes for top and underlying measures
496 26417 : measure->checkEndOfMeasureChange();
497 26417 : if (measure->isMMRest()) {
498 112 : Measure* mmLast = measure->mmRestLast();
499 112 : if (mmLast) {
500 112 : mmLast->checkEndOfMeasureChange();
501 : }
502 : }
503 26417 : if (nextMeasure->isMMRest()) {
504 86 : Measure* mmFirst = nextMeasure->mmRestFirst();
505 86 : if (mmFirst) {
506 86 : mmFirst->checkEndOfMeasureChange();
507 : }
508 : }
509 :
510 : // Sort segments at start of next measure
511 26417 : removeAndAddBeginSegments(nextMeasure);
512 26417 : if (nextMeasure->isMMRest()) {
513 86 : Measure* mmFirst = nextMeasure->mmRestFirst();
514 86 : if (mmFirst) {
515 86 : removeAndAddBeginSegments(mmFirst);
516 : }
517 : }
518 :
519 : // Sort segments at start of first measure
520 26417 : Measure* prevMeasure = measure->prevMeasure();
521 26417 : if (prevMeasure && prevMeasure == ctx.dom().firstMeasure()) {
522 2312 : removeAndAddBeginSegments(prevMeasure);
523 2312 : if (prevMeasure->isMMRest()) {
524 0 : Measure* mmFirst = prevMeasure->mmRestFirst();
525 0 : if (mmFirst) {
526 0 : removeAndAddBeginSegments(mmFirst);
527 : }
528 : }
529 : }
530 26417 : }
531 :
532 28815 : void ModifyDom::removeAndAddBeginSegments(Measure* measure)
533 : {
534 28815 : std::vector<Segment*> segsToSort;
535 115282 : for (Segment& seg : measure->segments()) {
536 86467 : if (seg.rtick() != Fraction(0, 1) || seg.isChordRestType() || seg.isEndBarLineType()) {
537 74533 : continue;
538 : }
539 :
540 11934 : segsToSort.push_back(&seg);
541 : }
542 :
543 : // Re-add the segments. They will be placed in their correct positions
544 40749 : for (Segment* seg : segsToSort) {
545 11934 : measure->segments().remove(seg);
546 : }
547 40749 : for (Segment* seg : segsToSort) {
548 11934 : measure->add(seg);
549 : }
550 28815 : }
|