MCC
Loading...
Searching...
No Matches
Pitch.h
1#ifndef MCC_PITCH_PITCH_H
2#define MCC_PITCH_PITCH_H
3
4#include <MCC_BuildSettings.h>
5
6#include <stdint.h>
7
8#include <Foundation/Math/Arithmetic.h>
9
10#include <MCC/Pitch/Accidental.h>
11#include <MCC/Pitch/PitchClass.h>
12#include <MCC/Pitch/ChromaticIndex.h>
13#include <MCC/Pitch/Letter.h>
14#include <MCC/Pitch/NoteName.h>
15
16namespace MCC {
17
35class Pitch {
36public:
38 static constexpr int8_t MinimumOctave = -128;
39
41 static constexpr int8_t MaximumOctave = 127;
42
47 static constexpr int16_t InvalidDiatonicIndex = 32767;
48
49private:
50 MCC::NoteName _noteName;
51 int8_t _octave;
52
53public:
55 constexpr Pitch() noexcept : _noteName(), _octave(0) {}
56
62 constexpr Pitch(MCC::NoteName noteName, int32_t octave) noexcept
63 : _noteName(IsWritable(noteName, octave)
64 ? noteName
66 _octave(IsWritable(noteName, octave)
67 ? static_cast<int8_t>(octave)
68 : static_cast<int8_t>(0)) {}
69
71 constexpr Pitch(MCC::Letter letter, MCC::Accidental accidental,
72 int32_t octave) noexcept
73 : Pitch(MCC::NoteName(letter, accidental), octave) {}
74
76 constexpr Pitch(MCC::Letter letter, int32_t octave) noexcept
77 : Pitch(MCC::NoteName(letter), octave) {}
78
80 static constexpr Pitch Invalid() noexcept { return Pitch(); }
81
83 constexpr bool IsValid() const noexcept { return _noteName.IsValid(); }
84
86 constexpr MCC::NoteName NoteName() const noexcept { return _noteName; }
87
92 constexpr MCC::Letter Letter() const noexcept { return _noteName.Letter(); }
93
95 constexpr MCC::Accidental Accidental() const noexcept {
96 return _noteName.Accidental();
97 }
98
103 constexpr int8_t Octave() const noexcept { return _octave; }
104
109 MCC_CONSTEXPR14 int16_t DiatonicIndex() const noexcept {
110 if (!IsValid()) {
112 }
113 return static_cast<int16_t>(
114 _octave * LetterCount + MCC::DiatonicIndex(Letter()));
115 }
116
121 MCC_CONSTEXPR14 MCC::ChromaticIndex ChromaticIndex() const noexcept {
122 if (!IsValid()) {
124 }
125 return MCC::ChromaticIndex(
126 (static_cast<int32_t>(_octave) + 1) * MCC::PitchClass::Count +
127 NaturalSemitone(Letter()) + Accidental().Semitones());
128 }
129
134 MCC_CONSTEXPR14 MCC::PitchClass PitchClass() const noexcept {
135 return _noteName.PitchClass();
136 }
137
146 MCC_CONSTEXPR14 Pitch MovedDiatonically(int32_t steps) const noexcept {
147 if (!IsValid() || steps < -2 * DiatonicSpan || steps > 2 * DiatonicSpan) {
148 return Invalid();
149 }
150 const int32_t index = DiatonicIndex() + steps;
151 return Pitch(
153 static_cast<MCC::Letter>(
154 Foundation::Math::FloorMod(index, LetterCount)),
155 Accidental()),
156 Foundation::Math::FloorDiv(index, LetterCount));
157 }
158
164 MCC_CONSTEXPR14 Pitch Altered(int32_t semitones) const noexcept {
165 if (!IsValid()) {
166 return Invalid();
167 }
168 return Pitch(_noteName.Altered(semitones), _octave);
169 }
170
175 MCC_CONSTEXPR14 Pitch MovedByOctaves(int32_t octaves) const noexcept {
176 if (!IsValid() ||
177 octaves < MinimumOctave - MaximumOctave ||
178 octaves > MaximumOctave - MinimumOctave) {
179 return Invalid();
180 }
181 return Pitch(_noteName, _octave + octaves);
182 }
183
188 friend constexpr bool operator==(Pitch a, Pitch b) noexcept {
189 return a._noteName == b._noteName && a._octave == b._octave;
190 }
191
192 friend constexpr bool operator!=(Pitch a, Pitch b) noexcept {
193 return !(a == b);
194 }
195
201 friend MCC_CONSTEXPR14 bool operator<(Pitch a, Pitch b) noexcept {
202 if (!a.IsValid() || !b.IsValid()) {
203 return a.IsValid() && !b.IsValid();
204 }
205 return (a._octave != b._octave)
206 ? a._octave < b._octave
207 : a._noteName < b._noteName;
208 }
209
210 friend MCC_CONSTEXPR14 bool operator>(Pitch a, Pitch b) noexcept {
211 return b < a;
212 }
213
214 friend MCC_CONSTEXPR14 bool operator<=(Pitch a, Pitch b) noexcept {
215 return !(b < a);
216 }
217
218 friend MCC_CONSTEXPR14 bool operator>=(Pitch a, Pitch b) noexcept {
219 return !(a < b);
220 }
221
222private:
223 // Number of diatonic positions between the lowest and highest pitch.
224 static constexpr int32_t DiatonicSpan =
225 (static_cast<int32_t>(MaximumOctave) - MinimumOctave + 1) * LetterCount;
226
227 static constexpr bool IsWritable(MCC::NoteName noteName,
228 int32_t octave) noexcept {
229 return noteName.IsValid() &&
230 octave >= MinimumOctave && octave <= MaximumOctave;
231 }
232};
233
240constexpr bool IsEnharmonic(Pitch a, Pitch b) noexcept {
241 return a.IsValid() && b.IsValid() && a.ChromaticIndex() == b.ChromaticIndex();
242}
243
250MCC_CONSTEXPR14 bool IsLowerThan(Pitch a, Pitch b) noexcept {
251 if (!a.IsValid() || !b.IsValid()) {
252 return a.IsValid() && !b.IsValid();
253 }
254 return (a.ChromaticIndex() != b.ChromaticIndex())
255 ? a.ChromaticIndex() < b.ChromaticIndex()
256 : a < b;
257}
258
259} // namespace MCC
260
261#endif // MCC_PITCH_PITCH_H
Chromatic alteration of a letter, from -4 (quadruple flat) to +4 (quadruple sharp).
Definition Accidental.h:20
constexpr Accidental() noexcept
Creates the invalid accidental (SPEC-ERR-2).
Definition Accidental.h:39
Absolute semitone position of a pitch, with origin C-1 = 0.
Definition ChromaticIndex.h:26
static constexpr ChromaticIndex Invalid() noexcept
Returns the invalid index.
Definition ChromaticIndex.h:57
Written note name: a letter plus an accidental, without octave.
Definition NoteName.h:29
static constexpr NoteName Invalid() noexcept
Returns the invalid note name.
Definition NoteName.h:59
Pitch class 0-11 with spelling discarded (C = 0).
Definition PitchClass.h:21
static constexpr uint8_t Count
Number of pitch classes in an octave.
Definition PitchClass.h:24
constexpr PitchClass() noexcept
Creates the invalid pitch class (SPEC-ERR-2).
Definition PitchClass.h:37
Written absolute pitch: a note name plus an octave.
Definition Pitch.h:35
constexpr Pitch(MCC::NoteName noteName, int32_t octave) noexcept
Creates noteName written in octave. An invalid note name or an octave outside [-128,...
Definition Pitch.h:62
constexpr Pitch() noexcept
Creates the invalid pitch (SPEC-ERR-2).
Definition Pitch.h:55
static constexpr Pitch Invalid() noexcept
Returns the invalid pitch.
Definition Pitch.h:80
constexpr Pitch(MCC::Letter letter, MCC::Accidental accidental, int32_t octave) noexcept
Creates letter + accidental written in octave.
Definition Pitch.h:71
static constexpr int8_t MinimumOctave
Lowest supported octave.
Definition Pitch.h:38
static constexpr int16_t InvalidDiatonicIndex
Sentinel returned by DiatonicIndex() for the invalid pitch (SPEC-ERR-7). Do not rely on it; check IsV...
Definition Pitch.h:47
MCC_CONSTEXPR14 Pitch Altered(int32_t semitones) const noexcept
Keeps the letter and octave and alters the accidental by semitones; outside [-4, +4] the result is in...
Definition Pitch.h:164
constexpr MCC::NoteName NoteName() const noexcept
Returns the written note name; invalid for the invalid pitch.
Definition Pitch.h:86
friend MCC_CONSTEXPR14 bool operator<(Pitch a, Pitch b) noexcept
Written order: octave, then letter, then accidental (SPEC-ORD-5). B#3 < Cb4 although B#3 sounds highe...
Definition Pitch.h:201
constexpr bool IsValid() const noexcept
Returns true unless this is the invalid pitch.
Definition Pitch.h:83
MCC_CONSTEXPR14 MCC::ChromaticIndex ChromaticIndex() const noexcept
Returns (octave + 1) * 12 + letterSemitone + accidental (SPEC-ORD-3); the invalid pitch yields the in...
Definition Pitch.h:121
constexpr MCC::Accidental Accidental() const noexcept
Returns the written accidental; invalid for the invalid pitch.
Definition Pitch.h:95
MCC_CONSTEXPR14 Pitch MovedByOctaves(int32_t octaves) const noexcept
Moves the pitch by octaves octaves, keeping its spelling. The result is invalid outside [-128,...
Definition Pitch.h:175
constexpr MCC::Letter Letter() const noexcept
Returns the written letter, or Letter::C for the invalid pitch (SPEC-ERR-7).
Definition Pitch.h:92
MCC_CONSTEXPR14 Pitch MovedDiatonically(int32_t steps) const noexcept
Moves the letter by steps diatonic letters, changing octave between B and C, and keeps the written ac...
Definition Pitch.h:146
MCC_CONSTEXPR14 MCC::PitchClass PitchClass() const noexcept
Returns the pitch class of the written note name (SPEC-ORD-4); the invalid pitch yields the invalid c...
Definition Pitch.h:134
constexpr int8_t Octave() const noexcept
Returns the written octave, or 0 for the invalid pitch (SPEC-ERR-7).
Definition Pitch.h:103
constexpr Pitch(MCC::Letter letter, int32_t octave) noexcept
Creates the natural letter written in octave.
Definition Pitch.h:76
friend constexpr bool operator==(Pitch a, Pitch b) noexcept
Written equality: letter, accidental and octave (SPEC-EQ-1). All invalid pitches are equal (SPEC-ERR-...
Definition Pitch.h:188
MCC_CONSTEXPR14 int16_t DiatonicIndex() const noexcept
Returns octave * 7 + letterIndex (SPEC-ORD-2), or InvalidDiatonicIndex for the invalid pitch (SPEC-ER...
Definition Pitch.h:109
static constexpr int8_t MaximumOctave
Highest supported octave.
Definition Pitch.h:41
constexpr uint8_t LetterCount
Number of diatonic letters.
Definition Letter.h:33
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 bool IsEnharmonic(Pitch a, Pitch b) noexcept
Returns true when a and b are valid and have the same chromatic index (SPEC-EQ-2): B#3 and C4 are enh...
Definition Pitch.h:240
constexpr uint8_t DiatonicIndex(Letter letter) noexcept
Returns the diatonic index of letter: C = 0 ... B = 6.
Definition Letter.h:49
MCC_CONSTEXPR14 bool IsLowerThan(Pitch a, Pitch b) noexcept
Pitch-height order (SPEC-ORD-6): true when a sounds lower than b, with enharmonic ties broken by writ...
Definition Pitch.h:250
Letter
Diatonic letter name.
Definition Letter.h:22
Music Composition Core public namespace.
Definition Version.h:4