MCC
Loading...
Searching...
No Matches
Transposition.h
1#ifndef MCC_INTERVAL_TRANSPOSITION_H
2#define MCC_INTERVAL_TRANSPOSITION_H
3
4#include <MCC_BuildSettings.h>
5
6#include <stdint.h>
7
8#include <Foundation/Math/Arithmetic.h>
9
10#include <MCC/Interval/Interval.h>
11#include <MCC/Pitch/Accidental.h>
12#include <MCC/Pitch/Letter.h>
13#include <MCC/Pitch/NoteName.h>
14#include <MCC/Pitch/Pitch.h>
15
16namespace MCC {
17
29MCC_CONSTEXPR14 Interval IntervalBetween(Pitch from, Pitch to) noexcept {
30 if (!from.IsValid() || !to.IsValid()) {
31 return Interval::Invalid();
32 }
34 static_cast<int32_t>(to.DiatonicIndex()) - from.DiatonicIndex(),
35 static_cast<int32_t>(to.ChromaticIndex().Value()) -
36 from.ChromaticIndex().Value());
37}
38
47MCC_CONSTEXPR14 Interval IntervalBetween(NoteName from, NoteName to) noexcept {
48 if (!from.IsValid() || !to.IsValid()) {
49 return Interval::Invalid();
50 }
51 const int32_t fromIndex = DiatonicIndex(from.Letter());
52 const int32_t toIndex = DiatonicIndex(to.Letter());
53 const int32_t steps = Foundation::Math::FloorMod(toIndex - fromIndex, LetterCount);
54 const int32_t wrap = (toIndex < fromIndex) ? 12 : 0;
55 const int32_t semitones =
56 NaturalSemitone(to.Letter()) + to.Accidental().Semitones() + wrap -
57 NaturalSemitone(from.Letter()) - from.Accidental().Semitones();
58 return Interval::FromSteps(steps, semitones);
59}
60
71MCC_CONSTEXPR14 Pitch operator+(Pitch pitch, Interval interval) noexcept {
72 if (!pitch.IsValid() || !interval.IsValid()) {
73 return Pitch::Invalid();
74 }
75 const int32_t diatonic =
76 static_cast<int32_t>(pitch.DiatonicIndex()) + interval.DiatonicSteps();
77 const int32_t chromatic =
78 static_cast<int32_t>(pitch.ChromaticIndex().Value()) + interval.Semitones();
79 const Letter letter =
80 static_cast<Letter>(Foundation::Math::FloorMod(diatonic, LetterCount));
81 const int32_t octave = Foundation::Math::FloorDiv(diatonic, LetterCount);
82 const int32_t natural = (octave + 1) * 12 + NaturalSemitone(letter);
83 return Pitch(letter, Accidental(chromatic - natural), octave);
84}
85
90MCC_CONSTEXPR14 Pitch operator-(Pitch pitch, Interval interval) noexcept {
91 return pitch + interval.Reversed();
92}
93
103MCC_CONSTEXPR14 NoteName operator+(NoteName noteName, Interval interval) noexcept {
104 if (!noteName.IsValid() || !interval.IsValid()) {
105 return NoteName::Invalid();
106 }
107 // Write the note name in octave 0, transpose it by the simple interval
108 // (at most one octave, so the octave stays in range) and drop the
109 // octave. An accidental overflow yields the invalid pitch, whose note
110 // name is invalid.
111 return (Pitch(noteName, 0) + interval.Simple()).NoteName();
112}
113
118MCC_CONSTEXPR14 NoteName operator-(NoteName noteName, Interval interval) noexcept {
119 return noteName + interval.Reversed();
120}
121
122} // namespace MCC
123
124#endif // MCC_INTERVAL_TRANSPOSITION_H
Chromatic alteration of a letter, from -4 (quadruple flat) to +4 (quadruple sharp).
Definition Accidental.h:20
Directed interval: a diatonic step count and a chromatic semitone count (SPEC-INT-1).
Definition Interval.h:30
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 Interval Invalid() noexcept
Returns the invalid interval.
Definition Interval.h:139
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
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
MCC_CONSTEXPR14 Pitch operator+(Pitch pitch, Interval interval) noexcept
Transposes pitch by interval preserving spelling (SPEC-INT-7): the letter moves by the diatonic steps...
Definition Transposition.h:71
MCC_CONSTEXPR14 Pitch operator-(Pitch pitch, Interval interval) noexcept
Transposes pitch down by interval: pitch + interval.Reversed().
Definition Transposition.h:90
MCC_CONSTEXPR14 Interval IntervalBetween(Pitch from, Pitch to) noexcept
Returns the directed interval from from to to (SPEC-INT-1): the difference of their diatonic and chro...
Definition Transposition.h:29
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 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
Music Composition Core public namespace.
Definition Version.h:4