1#ifndef MCC_INTERVAL_INTERVAL_H
2#define MCC_INTERVAL_INTERVAL_H
4#include <MCC_BuildSettings.h>
8#include <MCC/Interval/IntervalDirection.h>
9#include <MCC/Interval/IntervalNumber.h>
10#include <MCC/Interval/IntervalQuality.h>
51 static constexpr int32_t ReferenceSemitones(int32_t simpleSteps)
noexcept {
52 return simpleSteps * 2 - (simpleSteps >= 3 ? 1 : 0);
55 static constexpr bool IsPerfectSteps(int32_t simpleSteps)
noexcept {
56 return simpleSteps == 0 || simpleSteps == 3 || simpleSteps == 4;
59 static constexpr int32_t Magnitude(int32_t value)
noexcept {
60 return value < 0 ? -value : value;
65 MCC_CONSTEXPR14 int32_t Deviation() const noexcept {
66 const int32_t sign = Sign();
67 const int32_t steps = sign * _steps;
68 const int32_t semitones = sign * _semitones;
69 return semitones - (steps / 7) * 12 - ReferenceSemitones(steps % 7);
72 constexpr int32_t Sign() const noexcept {
74 ? (_steps > 0 ? 1 : -1)
75 : (_semitones < 0 ? -1 : 1);
78 static MCC_CONSTEXPR14 IntervalQuality QualityFor(int32_t steps,
79 int32_t deviation)
noexcept {
80 if (IsPerfectSteps(steps % 7)) {
86 : IntervalQuality::Diminished(-deviation);
91 if (deviation == -1) {
96 : IntervalQuality::Diminished(-deviation - 1);
112 int32_t semitones)
noexcept {
114 if (diatonicSteps < -MaximumSteps || diatonicSteps >
MaximumSteps ||
119 candidate._steps =
static_cast<int16_t
>(diatonicSteps);
120 candidate._semitones =
static_cast<int16_t
>(semitones);
136 :
Interval(Build(quality, number, direction)) {}
157 constexpr int16_t
Semitones() const noexcept {
return _semitones; }
164 if (!
IsValid() || (_steps == 0 && _semitones == 0)) {
165 return IntervalDirection::Unison;
167 return Sign() > 0 ? IntervalDirection::Ascending
168 : IntervalDirection::Descending;
184 return QualityFor(Magnitude(_steps), Deviation());
199 if (!
IsValid() || Magnitude(_steps) <= 7) {
202 const int32_t sign = Sign();
203 const int32_t octaves = (Magnitude(_steps) - 1) / 7;
204 return FromSteps(_steps - sign * octaves * 7,
205 _semitones - sign * octaves * 12);
222 const int32_t sign = simple.Sign();
223 return FromSteps(sign * 7 - simple._steps, sign * 12 - simple._semitones);
231 return FromSteps(-
static_cast<int32_t
>(_steps),
232 -
static_cast<int32_t
>(_semitones));
241 if (!a.IsValid() || !b.IsValid()) {
244 return FromSteps(
static_cast<int32_t
>(a._steps) + b._steps,
245 static_cast<int32_t
>(a._semitones) + b._semitones);
254 return a._steps == b._steps && a._semitones == b._semitones;
262 static MCC_CONSTEXPR14
Interval Build(IntervalQuality quality, IntervalNumber number,
264 if (!quality.IsValid() || !number.IsValid()) {
267 const int32_t steps = number.Value() - 1;
268 const int32_t simpleSteps = steps % 7;
270 const int32_t count = quality.Count();
272 int32_t deviation = 0;
273 if (IsPerfectSteps(simpleSteps)) {
274 if (kind == IntervalQualityKind::Major ||
275 kind == IntervalQualityKind::Minor) {
278 deviation = (kind == IntervalQualityKind::Augmented) ? count
282 if (kind == IntervalQualityKind::Perfect) {
285 deviation = (kind == IntervalQualityKind::Augmented) ? count
295 if (deviation == 0) {
298 if (direction == IntervalDirection::Unison) {
301 }
else if (direction == IntervalDirection::Unison) {
305 const int32_t sign = (direction == IntervalDirection::Descending) ? -1 : 1;
306 const int32_t semitones =
307 (steps / 7) * 12 + ReferenceSemitones(simpleSteps) + deviation;
308 return FromSteps(sign * steps, sign * semitones);
319 return a.IsValid() && b.IsValid() && a.Semitones() == b.Semitones();
1-based interval number: 1 unison, 3 third, 8 octave, 10 tenth (SPEC-INT-2, SPEC-INT-3).
Definition IntervalNumber.h:19
constexpr bool IsSimple() const noexcept
Returns true for numbers 1-8 (SPEC-INT-3).
Definition IntervalNumber.h:56
static constexpr uint16_t Maximum
Widest number: Cbbbb-128 to B####127 spans 1791 steps.
Definition IntervalNumber.h:22
constexpr bool IsCompound() const noexcept
Returns true for numbers above 8 (SPEC-INT-3).
Definition IntervalNumber.h:59
static constexpr IntervalNumber Invalid() noexcept
Returns the invalid number.
Definition IntervalNumber.h:47
Interval quality: perfect, major, minor, or augmented/diminished repeated one to four times (SPEC-INT...
Definition IntervalQuality.h:30
static constexpr IntervalQuality Augmented(int32_t count=1) noexcept
Returns the quality augmented count times; a count outside [1, 4] is invalid (SPEC-INT-4).
Definition IntervalQuality.h:73
static constexpr IntervalQuality Minor() noexcept
Returns the minor quality.
Definition IntervalQuality.h:65
constexpr bool IsValid() const noexcept
Returns true unless this is the invalid quality.
Definition IntervalQuality.h:86
static constexpr IntervalQuality Invalid() noexcept
Returns the invalid quality.
Definition IntervalQuality.h:52
static constexpr IntervalQuality Perfect() noexcept
Returns the perfect quality.
Definition IntervalQuality.h:55
static constexpr IntervalQuality Major() noexcept
Returns the major quality.
Definition IntervalQuality.h:60
Directed interval: a diatonic step count and a chromatic semitone count (SPEC-INT-1).
Definition Interval.h:30
MCC_CONSTEXPR14 Interval Reversed() const noexcept
Returns the same interval in the opposite direction.
Definition Interval.h:227
MCC_CONSTEXPR14 IntervalQuality Quality() const noexcept
Returns the quality (SPEC-INT-4); invalid if invalid.
Definition Interval.h:180
constexpr Interval() noexcept
Creates the invalid interval (SPEC-ERR-2).
Definition Interval.h:101
constexpr int16_t Semitones() const noexcept
Returns the signed semitone count, or 0 for the invalid interval (SPEC-ERR-7).
Definition Interval.h:157
MCC_CONSTEXPR14 bool IsCompound() const noexcept
Returns true for numbers above 8 (SPEC-INT-3).
Definition Interval.h:191
MCC_CONSTEXPR14 bool IsSimple() const noexcept
Returns true for numbers 1-8 (SPEC-INT-3).
Definition Interval.h:188
static constexpr int16_t InvalidSteps
Sentinel returned by DiatonicSteps() for the invalid interval (SPEC-ERR-7). Do not rely on it; check ...
Definition Interval.h:42
constexpr int16_t DiatonicSteps() const noexcept
Returns the signed diatonic step count, or InvalidSteps for the invalid interval (SPEC-ERR-7).
Definition Interval.h:151
MCC_CONSTEXPR14 IntervalDirection Direction() const noexcept
Returns the direction (SPEC-INT-2); Unison for the perfect unison and for the invalid interval (SPEC-...
Definition Interval.h:163
static MCC_CONSTEXPR14 Interval FromSteps(int32_t diatonicSteps, int32_t semitones) noexcept
Creates the interval spanning diatonicSteps letters and semitones semitones, both signed (SPEC-INT-1)...
Definition Interval.h:111
static constexpr int16_t MaximumSteps
Largest step magnitude: IntervalNumber::Maximum - 1.
Definition Interval.h:33
MCC_CONSTEXPR14 IntervalNumber Number() const noexcept
Returns the 1-based number (SPEC-INT-2); invalid if invalid.
Definition Interval.h:172
constexpr bool IsValid() const noexcept
Returns true unless this is the invalid interval.
Definition Interval.h:145
MCC_CONSTEXPR14 Interval(IntervalQuality quality, IntervalNumber number, IntervalDirection direction=IntervalDirection::Ascending) noexcept
Creates the interval of quality and number in direction, for example Interval(IntervalQuality::Major(...
Definition Interval.h:134
static MCC_CONSTEXPR14 Interval Unison() noexcept
Returns the perfect unison.
Definition Interval.h:142
MCC_CONSTEXPR14 Interval Simple() const noexcept
Removes whole octaves while keeping direction and quality (SPEC-INT-3): a major tenth becomes a major...
Definition Interval.h:198
static constexpr Interval Invalid() noexcept
Returns the invalid interval.
Definition Interval.h:139
friend constexpr bool operator==(Interval a, Interval b) noexcept
Written equality: same steps and semitones. An augmented fourth and a diminished fifth are different ...
Definition Interval.h:253
MCC_CONSTEXPR14 Interval Inverted() const noexcept
Returns the inversion of the simple interval, in the same direction (SPEC-INT-6): numbers add up to 9...
Definition Interval.h:217
static constexpr int16_t MaximumSemitones
Largest semitone magnitude between two writable pitches.
Definition Interval.h:36
friend MCC_CONSTEXPR14 Interval operator+(Interval a, Interval b) noexcept
Adds two intervals by adding their steps and semitones: major third + minor third = perfect fifth....
Definition Interval.h:240
IntervalDirection
Direction of an interval (SPEC-INT-2).
Definition IntervalDirection.h:17
IntervalQualityKind
Kind of an interval quality.
Definition IntervalQuality.h:14
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
Music Composition Core public namespace.
Definition Version.h:4