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 "key.h"
24 :
25 : #include "accidental.h"
26 : #include "part.h"
27 : #include "pitchspelling.h"
28 : #include "score.h"
29 : #include "utils.h"
30 :
31 : #include "log.h"
32 :
33 : using namespace mu;
34 :
35 : namespace mu::engraving {
36 : // transposition table for microtonal accidentals
37 : const SymId accTable[] = {
38 : SymId::noSym,
39 : // standard accidentals
40 : SymId::accidentalTripleFlat,
41 : SymId::accidentalDoubleFlat,
42 : SymId::accidentalFlat,
43 : SymId::accidentalNatural,
44 : SymId::accidentalSharp,
45 : SymId::accidentalDoubleSharp,
46 : SymId::accidentalTripleSharp,
47 : SymId::noSym,
48 : // natural sharp
49 : SymId::accidentalNatural,
50 : SymId::accidentalNaturalSharp,
51 : SymId::accidentalSharp,
52 : SymId::noSym,
53 : // natural flat
54 : SymId::accidentalDoubleFlat,
55 : SymId::accidentalNaturalFlat,
56 : SymId::accidentalNatural,
57 : SymId::noSym,
58 : // natural sharp sharp
59 : SymId::accidentalSharp,
60 : SymId::accidentalSharpSharp,
61 : SymId::accidentalTripleSharp,
62 : SymId::noSym,
63 : // Gould quarter tone
64 : // arrow down
65 : SymId::accidentalFiveQuarterTonesFlatArrowDown,
66 : SymId::accidentalThreeQuarterTonesFlatArrowDown,
67 : SymId::accidentalQuarterToneFlatNaturalArrowDown,
68 : SymId::accidentalQuarterToneSharpArrowDown,
69 : SymId::accidentalThreeQuarterTonesSharpArrowDown,
70 : SymId::accidentalFiveQuarterTonesFlatArrowDown,
71 : SymId::noSym,
72 : // arrow up
73 : SymId::accidentalThreeQuarterTonesFlatArrowUp,
74 : SymId::accidentalQuarterToneFlatArrowUp,
75 : SymId::accidentalQuarterToneSharpNaturalArrowUp,
76 : SymId::accidentalThreeQuarterTonesSharpArrowUp,
77 : SymId::accidentalFiveQuarterTonesSharpArrowUp,
78 : SymId::noSym,
79 : // Stein-Zimmermann
80 : // basic
81 : SymId::accidentalThreeQuarterTonesFlatZimmermann,
82 : SymId::accidentalQuarterToneFlatStein,
83 : SymId::accidentalQuarterToneSharpStein,
84 : SymId::accidentalThreeQuarterTonesSharpStein,
85 : SymId::noSym,
86 : // narrow (as variant of above)
87 : SymId::accidentalNarrowReversedFlatAndFlat,
88 : SymId::accidentalNarrowReversedFlat,
89 : SymId::accidentalQuarterToneSharpStein,
90 : // Extended Helmholtz-Ellis (just intonation)
91 : // one syntonic comma down arrow
92 : SymId::accidentalDoubleFlatOneArrowDown,
93 : SymId::accidentalFlatOneArrowDown,
94 : SymId::accidentalNaturalOneArrowDown,
95 : SymId::accidentalSharpOneArrowDown,
96 : SymId::accidentalDoubleSharpOneArrowDown,
97 : SymId::noSym,
98 : // one syntonic comma up arrow
99 : SymId::accidentalDoubleFlatOneArrowUp,
100 : SymId::accidentalFlatOneArrowUp,
101 : SymId::accidentalNaturalOneArrowUp,
102 : SymId::accidentalSharpOneArrowUp,
103 : SymId::accidentalDoubleSharpOneArrowUp,
104 : SymId::noSym,
105 : // two syntonic commas down
106 : SymId::accidentalDoubleFlatTwoArrowsDown,
107 : SymId::accidentalFlatTwoArrowsDown,
108 : SymId::accidentalNaturalTwoArrowsDown,
109 : SymId::accidentalSharpTwoArrowsDown,
110 : SymId::accidentalDoubleSharpTwoArrowsDown,
111 : SymId::noSym,
112 : // two syntonic commas up
113 : SymId::accidentalDoubleFlatTwoArrowsUp,
114 : SymId::accidentalFlatTwoArrowsUp,
115 : SymId::accidentalNaturalTwoArrowsUp,
116 : SymId::accidentalSharpTwoArrowsUp,
117 : SymId::accidentalDoubleSharpTwoArrowsUp,
118 : SymId::noSym,
119 : // three syntonic commas down
120 : SymId::accidentalDoubleFlatThreeArrowsDown,
121 : SymId::accidentalFlatThreeArrowsDown,
122 : SymId::accidentalNaturalThreeArrowsDown,
123 : SymId::accidentalSharpThreeArrowsDown,
124 : SymId::accidentalDoubleSharpThreeArrowsDown,
125 : SymId::noSym,
126 : // three syntonic commas up
127 : SymId::accidentalDoubleFlatThreeArrowsUp,
128 : SymId::accidentalFlatThreeArrowsUp,
129 : SymId::accidentalNaturalThreeArrowsUp,
130 : SymId::accidentalSharpThreeArrowsUp,
131 : SymId::accidentalDoubleSharpThreeArrowsUp,
132 : SymId::noSym,
133 : // equal tempered semitone
134 : SymId::accidentalDoubleFlatEqualTempered,
135 : SymId::accidentalFlatEqualTempered,
136 : SymId::accidentalNaturalEqualTempered,
137 : SymId::accidentalSharpEqualTempered,
138 : SymId::accidentalDoubleSharpEqualTempered,
139 : SymId::noSym
140 : };
141 :
142 : //---------------------------------------------------------
143 : // enforceLimits - ensure _key
144 : // is within acceptable limits (-7 .. +7).
145 : // see KeySig::layout()
146 : //---------------------------------------------------------
147 :
148 1791060 : void KeySigEvent::enforceLimits(bool transposing)
149 : {
150 1791060 : if (m_key < Key::MIN) {
151 0 : m_key = Key::MIN;
152 0 : LOGD("key < -7");
153 1791060 : } else if (m_key > Key::MAX) {
154 4 : m_key = Key::MAX;
155 4 : LOGD("key > 7");
156 : }
157 :
158 1791060 : if (transposing) {
159 1553 : return;
160 : }
161 :
162 1789507 : if (m_concertKey < Key::MIN) {
163 0 : m_concertKey = Key::MIN;
164 0 : LOGD("key < -7");
165 1789507 : } else if (m_concertKey > Key::MAX) {
166 2 : m_concertKey = Key::MAX;
167 2 : LOGD("key > 7");
168 : }
169 : }
170 :
171 : //---------------------------------------------------------
172 : // print
173 : //---------------------------------------------------------
174 :
175 0 : void KeySigEvent::print() const
176 : {
177 0 : LOGD("<KeySigEvent: ");
178 0 : if (!isValid()) {
179 0 : LOGD("invalid>");
180 : } else {
181 0 : if (isAtonal()) {
182 0 : LOGD("atonal>");
183 0 : } else if (custom()) {
184 0 : LOGD("custom>");
185 : } else {
186 0 : LOGD("accidental %d>", int(m_key));
187 : }
188 : }
189 0 : }
190 :
191 : //---------------------------------------------------------
192 : // setKey
193 : //---------------------------------------------------------
194 :
195 1553 : void KeySigEvent::setKey(Key v)
196 : {
197 1553 : m_key = v;
198 1553 : enforceLimits(true);
199 1553 : }
200 :
201 : //---------------------------------------------------------
202 : // setConcertKey
203 : //---------------------------------------------------------
204 :
205 1789503 : void KeySigEvent::setConcertKey(Key v)
206 : {
207 1789503 : m_key = v;
208 1789503 : m_concertKey = v;
209 1789503 : enforceLimits();
210 1789503 : }
211 :
212 : //---------------------------------------------------------
213 : // setCustom
214 : //---------------------------------------------------------
215 :
216 29 : void KeySigEvent::setCustom(bool val)
217 : {
218 29 : m_custom = val;
219 29 : if (m_key == Key::INVALID) {
220 21 : m_concertKey = Key::C;
221 21 : m_key = Key::C;
222 : }
223 29 : }
224 :
225 : //---------------------------------------------------------
226 : // KeySigEvent::operator==
227 : //---------------------------------------------------------
228 :
229 78427 : bool KeySigEvent::operator==(const KeySigEvent& e) const
230 : {
231 78427 : if (e.m_custom != m_custom || e.m_mode != m_mode || e.m_forInstrumentChange != m_forInstrumentChange) {
232 62 : return false;
233 : }
234 78365 : if (m_custom && !isAtonal()) {
235 60 : if (e.m_customKeyDefs.size() != m_customKeyDefs.size()) {
236 0 : return false;
237 : }
238 68 : for (size_t i = 0; i < m_customKeyDefs.size(); ++i) {
239 : // check note and sym, don't care xAlt and octAlt
240 60 : if (e.m_customKeyDefs[i].degree != m_customKeyDefs[i].degree || e.m_customKeyDefs[i].sym != m_customKeyDefs[i].sym) {
241 52 : return false;
242 : }
243 : // TODO: position matters // does it?
244 : }
245 8 : return true;
246 : }
247 78305 : return e.m_concertKey == m_concertKey && e.m_key == m_key;
248 : }
249 :
250 : //---------------------------------------------------------
251 : // calculateInterval
252 : // Calculates the interval to move from one key to another
253 : //---------------------------------------------------------
254 :
255 25 : Interval calculateInterval(Key key1, Key key2)
256 : {
257 25 : int chromatic = 7 * ((int)key2 - (int)key1);
258 25 : chromatic = chromatic % 12;
259 25 : if (chromatic < 0) {
260 1 : chromatic += 12;
261 : }
262 25 : return Interval(chromatic);
263 : }
264 :
265 : //---------------------------------------------------------
266 : // initFromSubtype
267 : // for backward compatibility
268 : //---------------------------------------------------------
269 :
270 4 : void KeySigEvent::initFromSubtype(int st)
271 : {
272 : //anatoly-os: legacy code. I don't understand why it is so overcomplicated.
273 : //Did refactoring to avoid exception on MSVC, but left the same logic.
274 : struct {
275 : int _key : 4;
276 : int _naturalType : 4;
277 : unsigned _customType : 16;
278 : bool _custom : 1;
279 : bool _invalid : 1;
280 : } a;
281 :
282 4 : a._key = (st & 0xf);
283 4 : a._naturalType = (st >> 4) & 0xf;
284 4 : a._customType = (st >> 8) & 0xffff;
285 4 : a._custom = (st >> 24) & 0x1;
286 4 : a._invalid = (st >> 25) & 0x1;
287 : //end of legacy code
288 :
289 4 : m_key = Key(a._key);
290 4 : m_concertKey = m_key;
291 : // _customType = a._customType;
292 4 : m_custom = a._custom;
293 4 : if (a._invalid) {
294 0 : m_key = Key::INVALID;
295 : }
296 4 : enforceLimits();
297 4 : }
298 :
299 : //---------------------------------------------------------
300 : // accidentalVal
301 : //---------------------------------------------------------
302 :
303 56574 : AccidentalVal AccidentalState::accidentalVal(int line, bool& error) const
304 : {
305 56574 : if (line < MIN_ACC_STATE || line >= MAX_ACC_STATE) {
306 17 : error = true;
307 17 : return AccidentalVal::NATURAL;
308 : }
309 56557 : return AccidentalVal((m_state[line] & 0x0f) + int(AccidentalVal::MIN));
310 : }
311 :
312 : //---------------------------------------------------------
313 : // init
314 : // preset lines list with accidentals for given key
315 : //---------------------------------------------------------
316 :
317 : static const int ACC_STATE_NATURAL = int(AccidentalVal::NATURAL) - int(AccidentalVal::MIN);
318 : static const int ACC_STATE_FLAT = int(AccidentalVal::FLAT) - int(AccidentalVal::MIN);
319 : static const int ACC_STATE_SHARP = int(AccidentalVal::SHARP) - int(AccidentalVal::MIN);
320 :
321 53366 : void AccidentalState::init(Key key)
322 : {
323 53366 : memset(m_state, ACC_STATE_NATURAL, MAX_ACC_STATE);
324 : // The numerical value of key tells us the number of sharps (or flats, if negative) in the key signature
325 53366 : if (key > 0 && key <= Key::MAX) {
326 10676 : for (int i = 0; i < int(key); ++i) {
327 : // First F#, then C#, then G#, etc.
328 7568 : int idx = tpc2step(Tpc::TPC_F_S + i);
329 90638 : for (int octave = 0; octave < (11 * 7); octave += 7) {
330 83248 : int j = idx + octave;
331 83248 : if (j >= MAX_ACC_STATE) {
332 178 : break;
333 : }
334 83070 : m_state[j] = ACC_STATE_SHARP;
335 : }
336 : }
337 50258 : } else if (key < 0 && key >= Key::MIN) {
338 6262 : for (int i = 0; i > int(key); --i) {
339 : // First Bb, then Eb, then Ab, etc.
340 4459 : int idx = tpc2step(Tpc::TPC_B_B + i);
341 50993 : for (int octave = 0; octave < (11 * 7); octave += 7) {
342 49049 : int j = idx + octave;
343 49049 : if (j >= MAX_ACC_STATE) {
344 2515 : break;
345 : }
346 46534 : m_state[j] = ACC_STATE_FLAT;
347 : }
348 : }
349 : }
350 53366 : }
351 :
352 : //---------------------------------------------------------
353 : // init
354 : //---------------------------------------------------------
355 :
356 50626 : void AccidentalState::init(const KeySigEvent& keySig)
357 : {
358 50626 : init(keySig.key());
359 50626 : if (keySig.custom()) {
360 202 : for (const CustDef& d : keySig.customKeyDefs()) {
361 100 : SymId sym = keySig.symInKey(d.sym, d.degree);
362 100 : int degree = keySig.degInKey(d.degree);
363 100 : AccidentalVal a = sym2accidentalVal(sym);
364 1176 : for (int octave = 0; octave < (11 * 7); octave += 7) {
365 1100 : int i = degree + octave;
366 1100 : if (i >= MAX_ACC_STATE) {
367 24 : break;
368 : }
369 1076 : m_state[i] = static_cast<uint8_t>(int(a) - int(AccidentalVal::MIN));
370 : }
371 : }
372 : }
373 50626 : m_forceRestateAccidental.fill(false);
374 50626 : }
375 :
376 : //---------------------------------------------------------
377 : // accidentalVal
378 : //---------------------------------------------------------
379 :
380 693 : AccidentalVal AccidentalState::accidentalVal(int line) const
381 : {
382 693 : assert(line >= MIN_ACC_STATE && line < MAX_ACC_STATE);
383 693 : return AccidentalVal((m_state[line] & 0x0f) + int(AccidentalVal::MIN));
384 : }
385 :
386 52503 : bool AccidentalState::forceRestateAccidental(int line) const
387 : {
388 52503 : assert(line >= MIN_ACC_STATE && line < MAX_ACC_STATE);
389 52503 : return m_forceRestateAccidental[line];
390 : }
391 :
392 : //---------------------------------------------------------
393 : // tieContext
394 : //---------------------------------------------------------
395 :
396 52517 : bool AccidentalState::tieContext(int line) const
397 : {
398 52517 : assert(line >= MIN_ACC_STATE && line < MAX_ACC_STATE);
399 52517 : return m_state[line] & TIE_CONTEXT;
400 : }
401 :
402 : //---------------------------------------------------------
403 : // setAccidentalVal
404 : //---------------------------------------------------------
405 :
406 4437 : void AccidentalState::setAccidentalVal(int line, AccidentalVal val, bool tieContext)
407 : {
408 4437 : assert(line >= MIN_ACC_STATE && line < MAX_ACC_STATE);
409 : // casts needed to work around a bug in Xcode 4.2 on Mac, see #25910
410 4437 : assert(int(val) >= int(AccidentalVal::MIN) && int(val) <= int(AccidentalVal::MAX));
411 4437 : m_state[line] = (int(val) - int(AccidentalVal::MIN)) | (tieContext ? TIE_CONTEXT : 0);
412 4437 : }
413 :
414 56393 : void AccidentalState::setForceRestateAccidental(int line, bool forceRestate)
415 : {
416 56393 : assert(line >= MIN_ACC_STATE && line < MAX_ACC_STATE);
417 56393 : m_forceRestateAccidental[line] = forceRestate;
418 56393 : }
419 :
420 : //---------------------------------------------------------
421 : // degInKey
422 : // degree to "absolute degree"
423 : // first degree in F major is F: 0 -> 3, ...
424 : //---------------------------------------------------------
425 :
426 396 : int KeySigEvent::degInKey(int degree) const
427 : {
428 396 : return (degree + ((static_cast<int>(key()) + 7) * 4)) % 7;
429 : }
430 :
431 : //---------------------------------------------------------
432 : // symInKey
433 : //---------------------------------------------------------
434 :
435 198 : SymId KeySigEvent::symInKey(SymId sym, int degree) const
436 : {
437 198 : degree = degInKey(degree);
438 198 : int keyval = static_cast<int>(key());
439 594 : int accIndex = std::distance(std::begin(accTable), std::find(std::begin(accTable), std::end(accTable), sym));
440 :
441 : // non transposed key
442 198 : if (keyval == 0 || std::abs(keyval) > 7) {
443 198 : return sym;
444 : }
445 :
446 : // sym is not transposable (it is not in table)
447 0 : if (!(accIndex < std::end(accTable) - std::begin(accTable))) {
448 0 : return SymId::noSym;
449 : }
450 :
451 0 : for (int i = 1; i <= std::abs(keyval); ++i) {
452 0 : if ((degree * 2 + 2) % 7 == (keyval < 0 ? 8 - i : i) % 7) {
453 0 : accIndex += keyval < 0 ? -1 : 1;
454 : }
455 : }
456 0 : return accTable[accIndex];
457 : }
458 : }
|