4#include <MCC_BuildSettings.h>
8#include <Foundation/Math/Arithmetic.h>
10#include <MCC/Key/KeySignature.h>
11#include <MCC/Pitch/ChromaticIndex.h>
12#include <MCC/Pitch/NoteName.h>
13#include <MCC/Pitch/Pitch.h>
14#include <MCC/Pitch/PitchClass.h>
15#include <MCC/Scale/Scales.h>
51 static constexpr int32_t LetterFifths(
Letter letter)
noexcept {
56 static constexpr int32_t ModeOffset(
KeyMode mode)
noexcept {
57 return 1 -
static_cast<int32_t
>(mode);
60 static constexpr int32_t SignatureFifths(
NoteName tonic,
KeyMode mode)
noexcept {
64 static constexpr bool IsMode(
KeyMode mode)
noexcept {
65 return static_cast<uint8_t
>(mode) <=
static_cast<uint8_t
>(KeyMode::Locrian);
70 constexpr Key() noexcept : _tonic(), _mode(
KeyMode::Major) {}
74 : _tonic(tonic.
IsValid() && IsMode(mode) &&
77 _mode(IsMode(mode) ? mode : KeyMode::Major) {}
81 if (!signature.IsValid() || !IsMode(mode)) {
85 const int32_t fifths = signature.Fifths() - ModeOffset(mode);
86 const int32_t order = Foundation::Math::FloorMod(fifths + 1, 7);
87 const int32_t accidental = Foundation::Math::FloorDiv(fifths + 1, 7);
88 const Letter letter =
static_cast<Letter>(((order + 6) * 4) % 7);
96 constexpr bool IsValid() const noexcept {
return _tonic.IsValid(); }
117 if (!
IsValid() || !pitchClass.IsValid()) {
121 const int32_t direction = signature.
Fifths() < 0 ? -1 : 1;
123 int32_t bestScore = 1000;
124 for (int32_t index = 0; index < 7; ++index) {
127 for (int32_t alteration = -1; alteration <= 1; ++alteration) {
133 const int32_t score = alteration == 0 ? 0
134 : 10 * (accidental < 0 ? -accidental : accidental) +
135 (alteration == direction ? 1 : 2);
136 if (score < bestScore) {
148 if (!index.IsValid()) {
155 const int32_t offset =
157 return MCC::Pitch(noteName, Foundation::Math::FloorDiv(index.Value() - offset, 12) - 1);
162 return a._tonic == b._tonic && (!a.IsValid() || a._mode == b._mode);
Chromatic alteration of a letter, from -4 (quadruple flat) to +4 (quadruple sharp).
Definition Accidental.h:20
constexpr int8_t Semitones() const noexcept
Returns the alteration in semitones, or InvalidValue for the invalid accidental (SPEC-ERR-7).
Definition Accidental.h:89
Absolute semitone position of a pitch, with origin C-1 = 0.
Definition ChromaticIndex.h:26
Key signature: zero to seven sharps or flats (SPEC-KEY-1).
Definition KeySignature.h:21
MCC_CONSTEXPR14 MCC::Accidental AccidentalOf(Letter letter) const noexcept
Returns the accidental the signature applies to letter: sharp, flat or natural; invalid for the inval...
Definition KeySignature.h:62
constexpr int8_t Fifths() const noexcept
Returns sharps as positive and flats as negative; 0 when invalid.
Definition KeySignature.h:46
MCC::Scale Scale() const noexcept
Returns the key's scale spelled from its tonic.
Definition Key.h:113
static MCC_CONSTEXPR14 Key FromSignature(KeySignature signature, KeyMode mode) noexcept
Returns the key with signature in mode (2 sharps + Minor = B minor).
Definition Key.h:80
MCC_CONSTEXPR14 NoteName Spell(MCC::PitchClass pitchClass) const noexcept
Writes pitchClass in this key's context (SPEC-KEY-3).
Definition Key.h:116
constexpr Key(NoteName tonic, KeyMode mode) noexcept
Creates tonic in mode; invalid beyond seven sharps or flats.
Definition Key.h:73
constexpr KeySignature Signature() const noexcept
Returns the key signature, or the invalid signature.
Definition Key.h:105
friend constexpr bool operator==(const Key &a, const Key &b) noexcept
Compares tonic spelling and mode.
Definition Key.h:161
constexpr Key() noexcept
Creates the invalid key (SPEC-ERR-2).
Definition Key.h:70
MCC_CONSTEXPR14 MCC::Pitch Spell(MCC::ChromaticIndex index) const noexcept
Writes a sounding chromatic index as a pitch in this key's context.
Definition Key.h:147
friend constexpr bool operator!=(const Key &a, const Key &b) noexcept
Negation of operator==.
Definition Key.h:166
constexpr NoteName Tonic() const noexcept
Returns the tonic.
Definition Key.h:99
static constexpr Key Invalid() noexcept
Returns the invalid key.
Definition Key.h:93
Scales::Id ScaleId() const noexcept
Returns the catalog scale of the mode, or Scales::Id::Invalid.
constexpr bool IsValid() const noexcept
Returns true unless this is the invalid key.
Definition Key.h:96
constexpr KeyMode Mode() const noexcept
Returns the mode.
Definition Key.h:102
Written note name: a letter plus an accidental, without octave.
Definition NoteName.h:29
constexpr MCC::Accidental Accidental() const noexcept
Returns the written accidental; invalid for the invalid note name.
Definition NoteName.h:76
constexpr MCC::Letter Letter() const noexcept
Returns the written letter, or Letter::C for the invalid note name (SPEC-ERR-7).
Definition NoteName.h:68
static constexpr NoteName Invalid() noexcept
Returns the invalid note name.
Definition NoteName.h:59
constexpr bool IsValid() const noexcept
Returns true unless this is the invalid note name.
Definition NoteName.h:62
MCC_CONSTEXPR14 MCC::PitchClass PitchClass() const noexcept
Returns (NaturalSemitone(letter) + accidental) mod 12, always in [0, 11] (SPEC-ORD-4)....
Definition NoteName.h:83
Pitch class 0-11 with spelling discarded (C = 0).
Definition PitchClass.h:21
Written absolute pitch: a note name plus an octave.
Definition Pitch.h:35
static constexpr Pitch Invalid() noexcept
Returns the invalid pitch.
Definition Pitch.h:80
KeyMode
Diatonic mode of a key, ordered from brightest to darkest.
Definition Key.h:23
MCC_CONSTEXPR14 uint8_t NaturalSemitone(Letter letter) noexcept
Returns the semitone offset of the natural letter above C: 0 2 4 5 7 9 11 (SPEC-ORD-1).
Definition Letter.h:58
constexpr uint8_t DiatonicIndex(Letter letter) noexcept
Returns the diatonic index of letter: C = 0 ... B = 6.
Definition Letter.h:49
Letter
Diatonic letter name.
Definition Letter.h:22
Scale Make(NoteName root, Id id) noexcept
Spells catalog entry id from root.
Definition Scales.h:107
Id
Stable catalog identifier.
Definition Scales.h:23
Music Composition Core public namespace.
Definition Version.h:4