24#ifndef MUSIC_THEORY_HPP
25#define MUSIC_THEORY_HPP
48constexpr std::array<int, STANDARD_DIATONIC_STEPS>
MAJOR_KEYMAP = { 0, 2, 4, 5, 7, 9, 11 };
49constexpr std::array<int, STANDARD_DIATONIC_STEPS>
MINOR_KEYMAP = { 0, 2, 3, 5, 7, 8, 10 };
91 constexpr Pitch(
NoteName pitchName,
int pitchOctave,
int pitchAlteration = 0)
101static constexpr std::array<music_theory::NoteName, music_theory::STANDARD_DIATONIC_STEPS> noteNames = {
102 NoteName::C, NoteName::D, NoteName::E, NoteName::F, NoteName::G, NoteName::A, NoteName::B
140 const int relativeOctave = pitch.
octave - 4;
151 static_assert(std::is_arithmetic_v<T>,
"sign requires a numeric type");
152 return n < T(0) ? T(-1) : T(1);
167 static_assert(std::is_integral_v<T>,
"signedModulus requires an integer type");
180 static_assert(std::is_integral_v<T>,
"positiveModulus requires an integer type");
207 const std::array<int, STANDARD_DIATONIC_STEPS>& keyMap =
MAJOR_KEYMAP)
220 const std::array<int, STANDARD_DIATONIC_STEPS>& keyMap =
MAJOR_KEYMAP)
245 return halfsteps - expectedHalfsteps;
257 if (std::abs(expectedKeyChange) > 1) {
276 if (std::abs(expectedKeyChange) > 1) {
303 int m_numberOfEdoDivisions;
304 std::vector<int> m_keyMap;
324 const std::optional <std::vector<int>>& keyMap = std::nullopt)
329 throw std::invalid_argument(
"The Transposer class only supports key map arrays of " + std::to_string(
STANDARD_DIATONIC_STEPS) +
" elements");
331 m_keyMap = keyMap.value();
332 }
else if (isMinor) {
349 m_displacement += interval;
356 const int stepSign =
sign(diatonicSteps);
357 for (
int i = 0; i < std::abs(diatonicSteps); ++i) {
358 const int keyStepEnharmonic = calcStepsBetweenScaleDegrees(m_displacement, m_displacement + stepSign);
360 m_alteration -= stepSign * keyStepEnharmonic;
388 const int stepsInAlteration = calcStepsInAlteration(interval, chromaticAlteration);
389 const int stepsInInterval = calcStepsInNormalizedInterval(intervalNormalized);
390 const int stepsInDiatonicInterval = calcStepsBetweenScaleDegrees(m_displacement, m_displacement + intervalNormalized);
392 const int effectiveAlteration = stepsInAlteration + stepsInInterval -
sign(interval) * stepsInDiatonicInterval;
395 m_alteration += effectiveAlteration;
406 while (std::abs(m_alteration) > 0) {
407 const int currSign =
sign(m_alteration);
408 const int currAbsDisp = std::abs(m_alteration);
410 if (std::abs(m_alteration) >= currAbsDisp) {
414 if (currSign !=
sign(m_alteration)) {
431 m_alteration += numberOfEdoDivisions;
446 return calcAbsoluteDivision(
displacement,
alteration) == calcAbsoluteDivision(m_displacement, m_alteration);
450 int calcFifthSteps()
const
453 static constexpr double kFifthsMultiplier = 0.5849625007211562;
454 return static_cast<int>(std::floor(m_numberOfEdoDivisions * kFifthsMultiplier) + 0.5);
457 int calcScaleDegree(
int interval)
const
460 int calcStepsBetweenScaleDegrees(
int firstDisplacement,
int secondDisplacement)
const
462 const int firstScaleDegree = calcScaleDegree(firstDisplacement);
463 const int secondScaleDegree = calcScaleDegree(secondDisplacement);
464 int result =
sign(secondDisplacement - firstDisplacement) * (m_keyMap[secondScaleDegree] - m_keyMap[firstScaleDegree]);
466 result += m_numberOfEdoDivisions;
471 int calcStepsInAlteration(
int interval,
int alteration)
const
473 const int fifthSteps = calcFifthSteps();
476 const int result =
sign(interval) * ((plusFifths * fifthSteps) + (minusOctaves * m_numberOfEdoDivisions));
480 int calcStepsInNormalizedInterval(
int intervalNormalized)
const
482 const int fifthSteps = calcFifthSteps();
483 const int index = std::abs(intervalNormalized);
487 return sign(intervalNormalized) * ((plusFifths * fifthSteps) + (minusOctaves * m_numberOfEdoDivisions));
492 const int baseStep = m_keyMap[scaleDegree];
497 const int octaveSteps = octaveCount * m_numberOfEdoDivisions;
498 const int chromaticSteps = calcStepsInAlteration(+1,
alteration);
500 return baseStep + chromaticSteps + octaveSteps;
Provides dependency-free transposition utilities that work with any scale that has 7 diatonic steps a...
Definition music_theory.hpp:299
int displacement() const
Return the current displacement value.
Definition music_theory.hpp:340
void chromaticTranspose(int interval, int chromaticAlteration)
Chromatically transposes by a specified chromatic interval.
Definition music_theory.hpp:385
void stepwiseTranspose(int numberOfEdoDivisions)
Transposes by the given number of EDO divisions and simplifies the spelling.
Definition music_theory.hpp:429
int alteration() const
Return the current chromatic alteration value.
Definition music_theory.hpp:343
Transposer(const Pitch &pitch)
Constructs a 12-EDO major-scale transposer for a spelled pitch.
Definition music_theory.hpp:309
void simplifySpelling()
Simplifies the spelling by reducing its alteration while preserving pitch.
Definition music_theory.hpp:404
Transposer(int displacement, int alteration, bool isMinor=false, int numberOfEdoDivisions=STANDARD_12EDO_STEPS, const std::optional< std::vector< int > > &keyMap=std::nullopt)
Constructor function.
Definition music_theory.hpp:322
void diatonicTranspose(int interval)
Transposes the displacement by the specified interval.
Definition music_theory.hpp:347
bool isEnharmonicEquivalent(int displacement, int alteration) const
Determines if the given displacement and alteration refer to the same pitch as the current state.
Definition music_theory.hpp:445
void enharmonicTranspose(int diatonicSteps)
Transposes enharmonically relative to the current values.
Definition music_theory.hpp:354
A dependency-free, header-only collection of useful functions for music theory.
DiatonicMode
Represents the seven standard diatonic musical modes.
Definition music_theory.hpp:110
@ Phrygian
minor with flat 2
@ Locrian
diminished with flat 2 and 5
@ Lydian
major with raised 4
@ Dorian
minor with raised 6
@ Mixolydian
major with flat 7
constexpr T signedModulus(T n, T d)
Calculates the modulus of positive and negative numbers in a predictable manner.
Definition music_theory.hpp:165
constexpr int STANDARD_NUMBER_OF_STAFFLINES
The standard number of lines on a staff.
Definition music_theory.hpp:44
constexpr int calcDisplacement(const Pitch &pitch)
Calculates the displacement value for a spelled pitch.
Definition music_theory.hpp:137
constexpr int calcPitchClass(NoteName noteName, int alteration=0, int numberOfEdoDivisions=STANDARD_12EDO_STEPS, const std::array< int, STANDARD_DIATONIC_STEPS > &keyMap=MAJOR_KEYMAP)
Calculates the pitch class of a spelled note name.
Definition music_theory.hpp:205
constexpr int calcAlterationFrom12EdoHalfsteps(int interval, int halfsteps)
Calculates the alteration in chromatic halfsteps for the specified interval/halfsteps combination.
Definition music_theory.hpp:240
constexpr std::array< int, STANDARD_DIATONIC_STEPS > MAJOR_KEYMAP
keymap for 12-EDO major keys
Definition music_theory.hpp:48
constexpr T sign(T n)
Calculates the sign of an integer.
Definition music_theory.hpp:149
ClefType
Represents the possible types of clef, irrespective of octave transposition.
Definition music_theory.hpp:123
@ TabSerif
Tablature clef (TAB) with serif font.
@ Percussion2
Narrow rectangle centered on middle staff line (corresponds to SMuFL glyph unpitchedPercussionClef2)
@ Tab
Tablature clef (TAB) with non-serif font.
@ Unknown
Unknown clef type (default value with {} initializer)
@ Percussion1
2 thick vertical lines centered on middle staff line (corresponds to SMuFL glyph unpitchedPercussionC...
constexpr int STANDARD_12EDO_STEPS
this can be overriden when constructing a Transposer instance.
Definition music_theory.hpp:46
constexpr int calcKeySigChangeFromInterval(int interval, int chromaticAlteration)
Calculates the resulting key signature change (sharps/flats) produced by a diatonic interval and chro...
Definition music_theory.hpp:271
constexpr int calcAlterationFromKeySigChange(int interval, int keySigChange)
Determines the chromatic alteration needed for a diatonic interval to produce a desired key signature...
Definition music_theory.hpp:252
constexpr bool calcTranspositionIsOctave(int displacement, int alteration)
Determines if the transposition values result in trasposing by one or more octaves.
Definition music_theory.hpp:286
constexpr int STANDARD_DIATONIC_STEPS
currently this is the only supported number of diatonic steps.
Definition music_theory.hpp:45
NoteName
The available note names in array order.
Definition music_theory.hpp:66
constexpr std::array< std::array< int, 2 >, STANDARD_DIATONIC_STEPS > DIATONIC_INTERVAL_ADJUSTMENTS
Array of chromatic intervals. Each member array contains.
Definition music_theory.hpp:54
constexpr int calc12EdoHalfstepsInInterval(int interval, int chromaticAlteration)
Calculates the number of 12-EDO chromatic halfsteps in the specified interval.
Definition music_theory.hpp:229
constexpr T positiveModulus(T n, T d, T *q=nullptr)
Calculates a positive modulus in the range [0, d-1], even for negative dividends.
Definition music_theory.hpp:178
constexpr std::array< int, STANDARD_DIATONIC_STEPS > MINOR_KEYMAP
keymap for 12-EDO minor keys
Definition music_theory.hpp:49
A spelled pitch, expressed relative to C4.
Definition music_theory.hpp:83
NoteName noteName
The diatonic note name.
Definition music_theory.hpp:96
constexpr Pitch()=default
Creates an unspecified pitch.
int octave
The octave number, where C4 is middle C.
Definition music_theory.hpp:97
constexpr Pitch(NoteName pitchName, int pitchOctave, int pitchAlteration=0)
Creates a spelled pitch.
Definition music_theory.hpp:91
int alteration
The alteration relative to the natural note name, in EDO divisions.
Definition music_theory.hpp:98