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 : #include "linkedobjects.h"
23 :
24 : #include "masterscore.h"
25 : #include "measure.h"
26 : #include "score.h"
27 : #include "staff.h"
28 :
29 : #include "log.h"
30 :
31 : using namespace mu::engraving;
32 :
33 10316 : bool LinkedObjects::contains(const EngravingObject* o) const
34 : {
35 10316 : return std::find(this->begin(), this->end(), o) != this->end();
36 : }
37 :
38 : //---------------------------------------------------------
39 : // mainElement
40 : // Returns "main" linked element which is expected to
41 : // be written to the file prior to others.
42 : //---------------------------------------------------------
43 :
44 16926 : EngravingObject* LinkedObjects::mainElement()
45 : {
46 16926 : if (empty()) {
47 0 : return nullptr;
48 : }
49 16926 : MasterScore* ms = front()->score()->masterScore();
50 16926 : const bool elements = front()->isEngravingItem();
51 16926 : const bool staves = front()->isStaff();
52 33852 : return *std::min_element(begin(), end(), [ms, elements, staves](EngravingObject* s1, EngravingObject* s2) {
53 16832 : if (s1->score() == ms && s2->score() != ms) {
54 33 : return true;
55 : }
56 16799 : if (s1->score() != s2->score()) {
57 12806 : return false;
58 : }
59 3993 : if (staves) {
60 1460 : return toStaff(s1)->idx() < toStaff(s2)->idx();
61 : }
62 2533 : if (elements) {
63 : // Now we compare either two elements from master score
64 : // or two elements from excerpt.
65 2533 : EngravingItem* e1 = toEngravingItem(s1);
66 2533 : EngravingItem* e2 = toEngravingItem(s2);
67 2533 : const track_idx_t tr1 = e1->track();
68 2533 : const track_idx_t tr2 = e2->track();
69 2533 : if (tr1 == tr2) {
70 6 : const Fraction tick1 = e1->tick();
71 6 : const Fraction tick2 = e2->tick();
72 6 : if (tick1 == tick2) {
73 6 : Measure* m1 = e1->findMeasure();
74 6 : Measure* m2 = e2->findMeasure();
75 6 : if (!m1 || !m2) {
76 0 : return false;
77 : }
78 :
79 : // MM rests are written to MSCX in the following order:
80 : // 1) first measure of MM rest (m->hasMMRest() == true);
81 : // 2) MM rest itself (m->isMMRest() == true);
82 : // 3) other measures of MM rest (m->hasMMRest() == false).
83 : //
84 : // As mainElement() must find the first element that
85 : // is going to be written to a file, MM rest writing
86 : // order should also be considered.
87 :
88 6 : if (m1->isMMRest() == m2->isMMRest()) {
89 : // no difference if both are MM rests or both are usual measures
90 6 : return false;
91 : }
92 :
93 : // MM rests may be generated but not written (e.g. if
94 : // saving a file right after disabling MM rests)
95 0 : bool mmRestsWritten = e1->style().styleB(Sid::createMultiMeasureRests);
96 0 : if (m1->tick() == m2->tick()) {
97 : // MM rests may be still enabled but the mmRest may have been removed by editing
98 : // NOTE: the fact that we have linked clones between the original measure and the MMRest
99 : // and we have to decide which one is the "main" one is really bad tech debt. We should not
100 : // use linked clones for that. Needs fix in future. [M.S.]
101 0 : bool oneIsMMRestCoveringOther = m1->mmRest() == m2 || m2->mmRest() == m1;
102 0 : mmRestsWritten &= oneIsMMRestCoveringOther;
103 : }
104 :
105 0 : if (m1->isMMRest()) {
106 : // m1 is earlier if m2 is *not* the first MM rest measure
107 0 : return mmRestsWritten && !m2->hasMMRest();
108 : }
109 0 : if (m2->isMMRest()) {
110 : // m1 is earlier if it *is* the first MM rest measure
111 0 : return !mmRestsWritten || m1->hasMMRest();
112 : }
113 0 : return false;
114 : }
115 0 : return tick1 < tick2;
116 : }
117 2527 : return tr1 < tr2;
118 : }
119 0 : return false;
120 16926 : });
121 : }
|