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