1 //=============================================================================
2 // MuseScore
3 // Music Composition & Notation
4 //
5 // Copyright (C) 2002-2011 Werner Schweer
6 //
7 // This program is free software; you can redistribute it and/or modify
8 // it under the terms of the GNU General Public License version 2
9 // as published by the Free Software Foundation and appearing in
10 // the file LICENCE.GPL
11 //=============================================================================
12
13 #include "key.h"
14 #include "xml.h"
15 #include "utils.h"
16 #include "score.h"
17 #include "pitchspelling.h"
18 #include "keylist.h"
19 #include "accidental.h"
20 #include "part.h"
21
22 namespace Ms {
23
24 //---------------------------------------------------------
25 // KeySigEvent
26 //---------------------------------------------------------
27
KeySigEvent(const KeySigEvent & k)28 KeySigEvent::KeySigEvent(const KeySigEvent& k)
29 {
30 _key = k._key;
31 _mode = k._mode;
32 _custom = k._custom;
33 _keySymbols = k._keySymbols;
34 _forInstrumentChange = k._forInstrumentChange;
35 }
36
37 //---------------------------------------------------------
38 // enforceLimits - ensure _key
39 // is within acceptable limits (-7 .. +7).
40 // see KeySig::layout()
41 //---------------------------------------------------------
42
enforceLimits()43 void KeySigEvent::enforceLimits()
44 {
45 if (_key < Key::MIN) {
46 _key = Key::MIN;
47 qDebug("key < -7");
48 }
49 else if (_key > Key::MAX) {
50 _key = Key::MAX;
51 qDebug("key > 7");
52 }
53 }
54
55 //---------------------------------------------------------
56 // print
57 //---------------------------------------------------------
58
print() const59 void KeySigEvent::print() const
60 {
61 qDebug("<KeySigEvent: ");
62 if (!isValid())
63 qDebug("invalid>");
64 else {
65 if (isAtonal())
66 qDebug("atonal>");
67 else if (custom())
68 qDebug("custom>");
69 else
70 qDebug("accidental %d>", int(_key));
71 }
72 }
73
74 //---------------------------------------------------------
75 // setKey
76 //---------------------------------------------------------
77
setKey(Key v)78 void KeySigEvent::setKey(Key v)
79 {
80 _key = v;
81 _custom = false;
82 enforceLimits();
83 }
84
85 //---------------------------------------------------------
86 // KeySigEvent::operator==
87 //---------------------------------------------------------
88
operator ==(const KeySigEvent & e) const89 bool KeySigEvent::operator==(const KeySigEvent& e) const
90 {
91 if (e._custom != _custom || e._mode != _mode || e._forInstrumentChange != _forInstrumentChange)
92 return false;
93 if (_custom && !isAtonal()) {
94 if (e._keySymbols.size() != _keySymbols.size())
95 return false;
96 for (int i = 0; i < _keySymbols.size(); ++i) {
97 if (e._keySymbols[i].sym != _keySymbols[i].sym)
98 return false;
99 // TODO: position matters
100 }
101 return true;
102 }
103 return e._key == _key;
104 }
105
106 //---------------------------------------------------------
107 // transposeKey
108 //---------------------------------------------------------
109
transposeKey(Key key,const Interval & interval,PreferSharpFlat prefer)110 Key transposeKey(Key key, const Interval& interval, PreferSharpFlat prefer)
111 {
112 int tpc = int(key) + 14;
113 tpc = transposeTpc(tpc, interval, false);
114
115 // change between 5/6/7 sharps and 7/6/5 flats
116 // other key signatures cannot be changed enharmonically
117 // without causing double-sharp/flat
118 // (-7 <=) tpc-14 <= -5, which has Cb, Gb, Db
119 if (tpc <= 9 && prefer == PreferSharpFlat::SHARPS)
120 tpc += 12;
121
122 // 5 <= tpc-14 <= 7, which has B, F#, C#, enharmonic with Cb, Gb, Db respectively
123 if (tpc >= 19 && tpc <= 21 && prefer == PreferSharpFlat::FLATS)
124 tpc -= 12;
125
126 // check for valid key sigs
127 if (tpc > 21)
128 tpc -= 12; // no more than 7 sharps in keysig
129 if (tpc < 7)
130 tpc += 12; // no more than 7 flats in keysig
131
132 return Key(tpc - 14);
133 }
134
135 //---------------------------------------------------------
136 // calculateInterval
137 // Calculates the interval to move from one key to another
138 //---------------------------------------------------------
139
calculateInterval(Key key1,Key key2)140 Interval calculateInterval(Key key1, Key key2)
141 {
142 int chromatic = 7 * ((int)key2 - (int)key1);
143 chromatic = chromatic % 12;
144 if (chromatic < 0)
145 chromatic += 12;
146 return Interval(chromatic);
147 }
148
149 //---------------------------------------------------------
150 // initFromSubtype
151 // for backward compatibility
152 //---------------------------------------------------------
153
initFromSubtype(int st)154 void KeySigEvent::initFromSubtype(int st)
155 {
156 //anatoly-os: legacy code. I don't understand why it is so overcomplicated.
157 //Did refactoring to avoid exception on MSVC, but left the same logic.
158 struct {
159 int _key:4;
160 int _naturalType:4;
161 unsigned _customType:16;
162 bool _custom : 1;
163 bool _invalid : 1;
164 } a;
165
166 a._key = (st & 0xf);
167 a._naturalType = (st >> 4) & 0xf;
168 a._customType = (st >> 8) & 0xffff;
169 a._custom = (st >> 24) & 0x1;
170 a._invalid = (st >> 25) & 0x1;
171 //end of legacy code
172
173 _key = Key(a._key);
174 // _customType = a._customType;
175 _custom = a._custom;
176 if (a._invalid)
177 _key = Key::INVALID;
178 enforceLimits();
179 }
180
181 //---------------------------------------------------------
182 // accidentalVal
183 //---------------------------------------------------------
184
accidentalVal(int line,bool & error) const185 AccidentalVal AccidentalState::accidentalVal(int line, bool &error) const
186 {
187 if (line < MIN_ACC_STATE || line >= MAX_ACC_STATE) {
188 error = true;
189 return AccidentalVal::NATURAL;
190 }
191 return AccidentalVal((state[line] & 0x0f) + int(AccidentalVal::MIN));
192 }
193
194 //---------------------------------------------------------
195 // init
196 // preset lines list with accidentals for given key
197 //---------------------------------------------------------
198
199 static const int ACC_STATE_NATURAL = int(AccidentalVal::NATURAL) - int(AccidentalVal::MIN);
200 static const int ACC_STATE_FLAT = int(AccidentalVal::FLAT) - int(AccidentalVal::MIN);
201 static const int ACC_STATE_SHARP = int(AccidentalVal::SHARP) - int(AccidentalVal::MIN);
202
init(Key key)203 void AccidentalState::init(Key key)
204 {
205 memset(state, ACC_STATE_NATURAL, MAX_ACC_STATE);
206 // The numerical value of key tells us the number of sharps (or flats, if negative) in the key signature
207 if (key > 0) {
208 for (int i = 0; i < int(key); ++i) {
209 // First F#, then C#, then G#, etc.
210 int idx = tpc2step(Tpc::TPC_F_S + i);
211 for (int octave = 0; octave < (11 * 7); octave += 7) {
212 int j = idx + octave;
213 if (j >= MAX_ACC_STATE)
214 break;
215 state[j] = ACC_STATE_SHARP;
216 }
217 }
218 }
219 else {
220 for (int i = 0; i > int(key); --i) {
221 // First Bb, then Eb, then Ab, etc.
222 int idx = tpc2step(Tpc::TPC_B_B + i);
223 for (int octave = 0; octave < (11 * 7); octave += 7) {
224 int j = idx + octave;
225 if (j >= MAX_ACC_STATE)
226 break;
227 state[j] = ACC_STATE_FLAT;
228 }
229 }
230 }
231 }
232
233 //---------------------------------------------------------
234 // init
235 //---------------------------------------------------------
236
init(const KeySigEvent & keySig,ClefType clef)237 void AccidentalState::init(const KeySigEvent& keySig, ClefType clef)
238 {
239 if (keySig.custom()) {
240 memset(state, ACC_STATE_NATURAL, MAX_ACC_STATE);
241 for (const KeySym& s : keySig.keySymbols()) {
242 AccidentalVal a = sym2accidentalVal(s.sym);
243 int line = int(s.spos.y() * 2);
244 int idx = relStep(line, clef) % 7;
245 for (int octave = 0; octave < (11 * 7); octave += 7) {
246 int i = idx + octave ;
247 if (i >= MAX_ACC_STATE)
248 break;
249 state[i] = int(a) - int(AccidentalVal::MIN);
250 }
251 }
252 }
253 else {
254 init(keySig.key());
255 }
256 }
257
258 //---------------------------------------------------------
259 // accidentalVal
260 //---------------------------------------------------------
261
accidentalVal(int line) const262 AccidentalVal AccidentalState::accidentalVal(int line) const
263 {
264 Q_ASSERT(line >= MIN_ACC_STATE && line < MAX_ACC_STATE);
265 return AccidentalVal((state[line] & 0x0f) + int(AccidentalVal::MIN));
266 }
267
268 //---------------------------------------------------------
269 // tieContext
270 //---------------------------------------------------------
271
tieContext(int line) const272 bool AccidentalState::tieContext(int line) const
273 {
274 Q_ASSERT(line >= MIN_ACC_STATE && line < MAX_ACC_STATE);
275 return state[line] & TIE_CONTEXT;
276 }
277
278 //---------------------------------------------------------
279 // setAccidentalVal
280 //---------------------------------------------------------
281
setAccidentalVal(int line,AccidentalVal val,bool tieContext)282 void AccidentalState::setAccidentalVal(int line, AccidentalVal val, bool tieContext)
283 {
284 Q_ASSERT(line >= MIN_ACC_STATE && line < MAX_ACC_STATE);
285 // casts needed to work around a bug in Xcode 4.2 on Mac, see #25910
286 Q_ASSERT(int(val) >= int(AccidentalVal::MIN) && int(val) <= int(AccidentalVal::MAX));
287 state[line] = (int(val) - int(AccidentalVal::MIN)) | (tieContext ? TIE_CONTEXT : 0);
288 }
289 }
290
291