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 "location.h"
24 :
25 : #include "chord.h"
26 : #include "engravingitem.h"
27 : #include "measure.h"
28 : #include "mscore.h"
29 : #include "note.h"
30 :
31 : #include "log.h"
32 :
33 : using namespace mu;
34 : using namespace mu::engraving;
35 :
36 : namespace mu::engraving {
37 : static constexpr Location absDefaults = Location::absolute();
38 :
39 : //---------------------------------------------------------
40 : // Location::track
41 : //---------------------------------------------------------
42 :
43 26663 : int Location::track() const
44 : {
45 26663 : if ((m_staff == absDefaults.m_staff) || (m_voice == absDefaults.m_voice)) {
46 12706 : return INT_MIN;
47 : }
48 13957 : return static_cast<int>(VOICES) * m_staff + m_voice;
49 : }
50 :
51 : //---------------------------------------------------------
52 : // Location::setTrack
53 : //---------------------------------------------------------
54 :
55 6933 : void Location::setTrack(int track)
56 : {
57 6933 : m_staff = track / VOICES;
58 6933 : m_voice = track % VOICES;
59 6933 : }
60 :
61 : //---------------------------------------------------------
62 : // Location::toAbsolute
63 : //---------------------------------------------------------
64 :
65 4203 : void Location::toAbsolute(const Location& ref)
66 : {
67 4203 : if (isAbsolute()) {
68 0 : return;
69 : }
70 4203 : m_staff += ref.m_staff;
71 4203 : m_voice += ref.m_voice;
72 4203 : m_measure += ref.m_measure;
73 4203 : m_frac += ref.m_frac;
74 4203 : m_note += ref.m_note;
75 4203 : m_rel = false;
76 : }
77 :
78 : //---------------------------------------------------------
79 : // Location::toRelative
80 : //---------------------------------------------------------
81 :
82 294 : void Location::toRelative(const Location& ref)
83 : {
84 294 : if (isRelative()) {
85 0 : return;
86 : }
87 294 : m_staff -= ref.m_staff;
88 294 : m_voice -= ref.m_voice;
89 294 : m_measure -= ref.m_measure;
90 294 : m_frac -= ref.m_frac;
91 294 : m_note -= ref.m_note;
92 294 : m_rel = true;
93 : }
94 :
95 : //---------------------------------------------------------
96 : // Location::fillPositionForElement
97 : // Fills default fields of Location by values relevant
98 : // for the given EngravingItem. This function fills only
99 : // position values, not dealing with parameters specific
100 : // for Chords and Notes, like grace index.
101 : //---------------------------------------------------------
102 :
103 3903 : void Location::fillPositionForElement(const EngravingItem* e, bool absfrac)
104 : {
105 3903 : assert(isAbsolute());
106 3903 : if (!e) {
107 0 : LOGW("Location::fillPositionForElement: element is nullptr");
108 0 : return;
109 : }
110 3903 : if (track() == absDefaults.track()) {
111 0 : setTrack(track(e));
112 : }
113 3903 : if (frac() == absDefaults.frac()) {
114 0 : setFrac(absfrac ? e->tick() : e->rtick());
115 : }
116 3903 : if (measure() == absDefaults.measure()) {
117 0 : setMeasure(absfrac ? 0 : measure(e));
118 : }
119 : }
120 :
121 : //---------------------------------------------------------
122 : // Location::fillForElement
123 : // Fills default fields of Location by values relevant
124 : // for the given EngravingItem, including parameters specific
125 : // for Chords and Notes.
126 : //---------------------------------------------------------
127 :
128 3903 : void Location::fillForElement(const EngravingItem* e, bool absfrac)
129 : {
130 3903 : assert(isAbsolute());
131 3903 : if (!e) {
132 0 : LOGW("Location::fillForElement: element is nullptr");
133 0 : return;
134 : }
135 :
136 3903 : fillPositionForElement(e, absfrac);
137 3903 : setGraceIndex(graceIndex(e));
138 3903 : setNote(note(e));
139 : }
140 :
141 : //---------------------------------------------------------
142 : // Location::forElement
143 : //---------------------------------------------------------
144 :
145 0 : Location Location::forElement(const EngravingItem* e, bool absfrac)
146 : {
147 0 : Location i = Location::absolute();
148 0 : i.fillForElement(e, absfrac);
149 0 : return i;
150 : }
151 :
152 : //---------------------------------------------------------
153 : // Location::positionForElement
154 : //---------------------------------------------------------
155 :
156 0 : Location Location::positionForElement(const EngravingItem* e, bool absfrac)
157 : {
158 0 : Location i = Location::absolute();
159 0 : i.fillPositionForElement(e, absfrac);
160 0 : return i;
161 : }
162 :
163 : //---------------------------------------------------------
164 : // Location::track
165 : //---------------------------------------------------------
166 :
167 0 : int Location::track(const EngravingItem* e)
168 : {
169 0 : int track = static_cast<int>(e->track());
170 0 : if (track < 0) {
171 0 : const MeasureBase* mb = e->findMeasureBase();
172 0 : if (mb && !mb->isMeasure()) {
173 : // Such elements are written in the first staff,
174 : // see writeMeasure() in rw/write/measurewrite.cpp
175 0 : track = 0;
176 : }
177 : }
178 0 : return track;
179 : }
180 :
181 : //---------------------------------------------------------
182 : // Location::measure
183 : //---------------------------------------------------------
184 :
185 0 : int Location::measure(const EngravingItem* e)
186 : {
187 0 : const Measure* m = toMeasure(e->findMeasure());
188 0 : if (m) {
189 0 : return m->measureIndex();
190 : }
191 0 : LOGW("Location::measure: cannot find element's measure (%s)", e->typeName());
192 0 : return 0;
193 : }
194 :
195 : //---------------------------------------------------------
196 : // Location::graceIndex
197 : //---------------------------------------------------------
198 :
199 3903 : int Location::graceIndex(const EngravingItem* e)
200 : {
201 3903 : if (e->isChord() || (e->ownershipParent() && e->ownershipParent()->isChord())) {
202 2951 : const Chord* ch = e->isChord() ? toChord(e) : toChord(e->ownershipParent());
203 2951 : if (ch->isGrace()) {
204 74 : return static_cast<int>(ch->graceIndex());
205 : }
206 : }
207 3829 : return absDefaults.graceIndex();
208 : }
209 :
210 : //---------------------------------------------------------
211 : // Location::note
212 : //---------------------------------------------------------
213 :
214 3903 : int Location::note(const EngravingItem* e)
215 : {
216 3903 : if (e->isNote()) {
217 2426 : const Note* n = toNote(e);
218 2426 : const std::vector<Note*>& notes = n->chord()->notes();
219 2426 : if (notes.size() == 1) {
220 2259 : return 0;
221 : }
222 : size_t noteIdx;
223 326 : for (noteIdx = 0; noteIdx < notes.size(); ++noteIdx) {
224 326 : if (n == notes.at(noteIdx)) {
225 167 : break;
226 : }
227 : }
228 167 : return static_cast<int>(noteIdx);
229 : }
230 1477 : return absDefaults.note();
231 : }
232 :
233 : //---------------------------------------------------------
234 : // Location::getLocationProperty
235 : //---------------------------------------------------------
236 :
237 0 : PropertyValue Location::getLocationProperty(Pid pid, const EngravingItem* start, const EngravingItem* end)
238 : {
239 0 : if (!start || !end) {
240 0 : return 0;
241 : }
242 0 : switch (pid) {
243 0 : case Pid::LOCATION_STAVES:
244 0 : return (track(start) / VOICES) - (track(end) / VOICES);
245 0 : case Pid::LOCATION_VOICES:
246 0 : return (track(start) % VOICES) - (track(end) / VOICES);
247 0 : case Pid::LOCATION_MEASURES:
248 0 : return measure(end) - measure(start);
249 0 : case Pid::LOCATION_FRACTIONS:
250 0 : return end->rtick() - start->rtick();
251 0 : case Pid::LOCATION_GRACE:
252 0 : return graceIndex(start) - graceIndex(end);
253 0 : case Pid::LOCATION_NOTE:
254 0 : return note(start) - note(end);
255 0 : default:
256 0 : return PropertyValue();
257 : }
258 : }
259 :
260 : //---------------------------------------------------------
261 : // Location::operator==
262 : //---------------------------------------------------------
263 :
264 24305 : bool Location::operator==(const Location& pi2) const
265 : {
266 24305 : const Location& pi1 = *this;
267 24305 : return (pi1.m_frac == pi2.m_frac)
268 6731 : && (pi1.m_measure == pi2.m_measure)
269 6719 : && (pi1.m_voice == pi2.m_voice)
270 6608 : && (pi1.m_staff == pi2.m_staff)
271 6594 : && (pi1.m_graceIndex == pi2.m_graceIndex)
272 31036 : && (pi1.m_note == pi2.m_note)
273 : ;
274 : }
275 : }
|