2012-05-26 14:26:10 +02:00
|
|
|
//=============================================================================
|
|
|
|
// MuseScore
|
|
|
|
// Music Composition & Notation
|
|
|
|
//
|
|
|
|
// Copyright (C) 2002-2011 Werner Schweer
|
|
|
|
//
|
|
|
|
// This program is free software; you can redistribute it and/or modify
|
|
|
|
// it under the terms of the GNU General Public License version 2
|
|
|
|
// as published by the Free Software Foundation and appearing in
|
|
|
|
// the file LICENCE.GPL
|
|
|
|
//=============================================================================
|
|
|
|
|
|
|
|
#include "key.h"
|
|
|
|
#include "xml.h"
|
|
|
|
#include "utils.h"
|
|
|
|
#include "score.h"
|
|
|
|
#include "pitchspelling.h"
|
2014-06-03 15:28:10 +02:00
|
|
|
#include "keylist.h"
|
2017-02-13 12:42:54 +01:00
|
|
|
#include "accidental.h"
|
2012-05-26 14:26:10 +02:00
|
|
|
|
2013-05-13 18:49:17 +02:00
|
|
|
namespace Ms {
|
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// KeySigEvent
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2014-12-04 14:40:26 +01:00
|
|
|
KeySigEvent::KeySigEvent(const KeySigEvent& k)
|
|
|
|
{
|
|
|
|
_key = k._key;
|
2015-06-05 01:53:47 +02:00
|
|
|
_mode = k._mode;
|
2014-12-04 14:40:26 +01:00
|
|
|
_custom = k._custom;
|
|
|
|
_keySymbols = k._keySymbols;
|
|
|
|
}
|
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
//---------------------------------------------------------
|
2014-06-20 17:07:22 +02:00
|
|
|
// enforceLimits - ensure _key
|
2014-06-03 15:28:10 +02:00
|
|
|
// is within acceptable limits (-7 .. +7).
|
2012-05-26 14:26:10 +02:00
|
|
|
// see KeySig::layout()
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void KeySigEvent::enforceLimits()
|
|
|
|
{
|
2014-06-20 17:07:22 +02:00
|
|
|
if (_key < Key::MIN) {
|
|
|
|
_key = Key::MIN;
|
2017-11-30 13:05:36 +01:00
|
|
|
qDebug("key < -7");
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
2014-06-20 17:07:22 +02:00
|
|
|
else if (_key > Key::MAX) {
|
|
|
|
_key = Key::MAX;
|
2017-11-30 13:05:36 +01:00
|
|
|
qDebug("key > 7");
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// print
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void KeySigEvent::print() const
|
|
|
|
{
|
|
|
|
qDebug("<KeySigEvent: ");
|
2014-12-04 14:40:26 +01:00
|
|
|
if (!isValid())
|
2012-05-26 14:26:10 +02:00
|
|
|
qDebug("invalid>");
|
|
|
|
else {
|
2015-06-05 01:53:47 +02:00
|
|
|
if (isAtonal())
|
|
|
|
qDebug("atonal>");
|
|
|
|
else if (custom())
|
2014-12-04 14:40:26 +01:00
|
|
|
qDebug("custom>");
|
2012-05-26 14:26:10 +02:00
|
|
|
else
|
2014-06-20 17:07:22 +02:00
|
|
|
qDebug("accidental %d>", int(_key));
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
2014-06-20 17:07:22 +02:00
|
|
|
// setKey
|
2012-05-26 14:26:10 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2014-06-20 17:07:22 +02:00
|
|
|
void KeySigEvent::setKey(Key v)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
2014-06-20 17:07:22 +02:00
|
|
|
_key = v;
|
|
|
|
_custom = false;
|
2012-05-26 14:26:10 +02:00
|
|
|
enforceLimits();
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// KeySigEvent::operator==
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
bool KeySigEvent::operator==(const KeySigEvent& e) const
|
|
|
|
{
|
2015-06-05 01:53:47 +02:00
|
|
|
if (e._custom != _custom || e._mode != _mode)
|
2012-05-26 14:26:10 +02:00
|
|
|
return false;
|
2015-06-05 01:53:47 +02:00
|
|
|
if (_custom && !isAtonal()) {
|
2014-12-04 14:40:26 +01:00
|
|
|
if (e._keySymbols.size() != _keySymbols.size())
|
|
|
|
return false;
|
|
|
|
for (int i = 0; i < _keySymbols.size(); ++i) {
|
|
|
|
if (e._keySymbols[i].sym != _keySymbols[i].sym)
|
|
|
|
return false;
|
|
|
|
// TODO: position matters
|
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
return true;
|
2014-12-04 14:40:26 +01:00
|
|
|
}
|
2014-12-08 18:02:17 +01:00
|
|
|
return e._key == _key;
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// transposeKey
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2014-06-20 17:07:22 +02:00
|
|
|
Key transposeKey(Key key, const Interval& interval)
|
2012-09-13 10:41:15 +02:00
|
|
|
{
|
2014-06-20 17:07:22 +02:00
|
|
|
int tpc = int(key) + 14;
|
|
|
|
tpc = transposeTpc(tpc, interval, false);
|
2012-09-13 10:37:34 +02:00
|
|
|
// check for valid key sigs
|
2014-06-20 17:07:22 +02:00
|
|
|
if (tpc > 21)
|
|
|
|
tpc -= 12; // no more than 7 sharps in keysig
|
|
|
|
if (tpc < 7)
|
|
|
|
tpc += 12; // no more than 7 flats in keysig
|
|
|
|
return Key(tpc - 14);
|
2012-09-13 10:41:15 +02:00
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// initFromSubtype
|
|
|
|
// for backward compatibility
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void KeySigEvent::initFromSubtype(int st)
|
|
|
|
{
|
2018-08-06 18:56:03 +02:00
|
|
|
//anatoly-os: legacy code. I don't understand why it is so overcomplicated.
|
|
|
|
//Did refactoring to avoid exception on MSVC, but left the same logic.
|
|
|
|
struct {
|
|
|
|
int _key:4;
|
|
|
|
int _naturalType:4;
|
|
|
|
unsigned _customType:16;
|
|
|
|
bool _custom : 1;
|
|
|
|
bool _invalid : 1;
|
|
|
|
} a;
|
|
|
|
|
|
|
|
a._key = (st & 0xf);
|
|
|
|
a._naturalType = (st >> 4) & 0xf;
|
|
|
|
a._customType = (st >> 8) & 0xffff;
|
|
|
|
a._custom = (st >> 24) & 0x1;
|
|
|
|
a._invalid = (st >> 25) & 0x1;
|
|
|
|
//end of legacy code
|
|
|
|
|
2014-06-20 17:07:22 +02:00
|
|
|
_key = Key(a._key);
|
2014-12-04 14:40:26 +01:00
|
|
|
// _customType = a._customType;
|
2012-05-26 14:26:10 +02:00
|
|
|
_custom = a._custom;
|
2014-12-04 14:40:26 +01:00
|
|
|
if (a._invalid)
|
|
|
|
_key = Key::INVALID;
|
2012-05-26 14:26:10 +02:00
|
|
|
enforceLimits();
|
|
|
|
}
|
|
|
|
|
2014-06-20 17:07:22 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// accidentalVal
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2016-01-21 14:33:32 +01:00
|
|
|
AccidentalVal AccidentalState::accidentalVal(int line, bool &error) const
|
2014-06-20 17:07:22 +02:00
|
|
|
{
|
2016-01-21 14:33:32 +01:00
|
|
|
if (line < MIN_ACC_STATE || line >= MAX_ACC_STATE) {
|
|
|
|
error = true;
|
|
|
|
return AccidentalVal::NATURAL;
|
|
|
|
}
|
2014-06-20 17:07:22 +02:00
|
|
|
return AccidentalVal((state[line] & 0x0f) - 2);
|
|
|
|
}
|
|
|
|
|
2017-02-13 12:42:54 +01:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// init
|
|
|
|
// preset lines list with accidentals for given key
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void AccidentalState::init(Key key)
|
|
|
|
{
|
|
|
|
memset(state, 2, MAX_ACC_STATE);
|
|
|
|
if (key > 0) {
|
|
|
|
for (int i = 0; i < int(key); ++i) {
|
|
|
|
int idx = tpc2step(20 + i);
|
|
|
|
for (int octave = 0; octave < (11 * 7); octave += 7) {
|
2018-08-17 15:06:15 +02:00
|
|
|
int j = idx + octave;
|
|
|
|
if (j >= MAX_ACC_STATE)
|
2017-02-13 12:42:54 +01:00
|
|
|
break;
|
2018-08-17 15:06:15 +02:00
|
|
|
state[j] = 1 + 2;
|
2017-02-13 12:42:54 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
for (int i = 0; i > int(key); --i) {
|
|
|
|
int idx = tpc2step(12 + i);
|
|
|
|
for (int octave = 0; octave < (11 * 7); octave += 7) {
|
2018-08-17 15:06:15 +02:00
|
|
|
int j = idx + octave ;
|
|
|
|
if (j >= MAX_ACC_STATE)
|
2017-02-13 12:42:54 +01:00
|
|
|
break;
|
2018-08-17 15:06:15 +02:00
|
|
|
state[j] = -1 + 2;
|
2017-02-13 12:42:54 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// init
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void AccidentalState::init(const KeySigEvent& keySig, ClefType clef)
|
|
|
|
{
|
|
|
|
if (keySig.custom()) {
|
|
|
|
memset(state, 2, MAX_ACC_STATE);
|
|
|
|
for (const KeySym& s : keySig.keySymbols()) {
|
|
|
|
AccidentalVal a = sym2accidentalVal(s.sym);
|
|
|
|
int line = int(s.spos.y() * 2);
|
|
|
|
int idx = relStep(line, clef) % 7;
|
|
|
|
for (int octave = 0; octave < (11 * 7); octave += 7) {
|
|
|
|
int i = idx + octave ;
|
|
|
|
if (i >= MAX_ACC_STATE)
|
|
|
|
break;
|
|
|
|
state[i] = int(a) + 2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
init(keySig.key());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// accidentalVal
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2016-01-21 14:33:32 +01:00
|
|
|
AccidentalVal AccidentalState::accidentalVal(int line) const
|
|
|
|
{
|
|
|
|
Q_ASSERT(line >= MIN_ACC_STATE && line < MAX_ACC_STATE);
|
2017-02-13 12:42:54 +01:00
|
|
|
return AccidentalVal((state[line] & 0x0f) - 2);
|
2016-01-21 14:33:32 +01:00
|
|
|
}
|
|
|
|
|
2014-06-20 17:07:22 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// tieContext
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
bool AccidentalState::tieContext(int line) const
|
|
|
|
{
|
2016-01-21 14:33:32 +01:00
|
|
|
Q_ASSERT(line >= MIN_ACC_STATE && line < MAX_ACC_STATE);
|
2014-06-20 17:07:22 +02:00
|
|
|
return state[line] & TIE_CONTEXT;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// setAccidentalVal
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void AccidentalState::setAccidentalVal(int line, AccidentalVal val, bool tieContext)
|
|
|
|
{
|
2016-01-21 14:33:32 +01:00
|
|
|
Q_ASSERT(line >= MIN_ACC_STATE && line < MAX_ACC_STATE);
|
2014-06-18 12:05:41 +02:00
|
|
|
// casts needed to work around a bug in Xcode 4.2 on Mac, see #25910
|
2014-06-10 17:06:02 +02:00
|
|
|
Q_ASSERT(int(val) >= int(AccidentalVal::FLAT2) && int(val) <= int(AccidentalVal::SHARP2));
|
2014-06-20 17:07:22 +02:00
|
|
|
state[line] = (int(val) + 2) | (tieContext ? TIE_CONTEXT : 0);
|
|
|
|
}
|
2013-05-13 18:49:17 +02:00
|
|
|
}
|
|
|
|
|