1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
|
#include <iostream>
#include <array>
#include <algorithm>
// ordered as in the standard chromatic scale. (AS_BF, FS_GF etc. are the semitones)
enum note { A, AS_BF, B, C, CS_DF, D, DS_EF, E, F, FS_GF, G, GS_AF };
std::ostream& operator<< ( std::ostream& stm, note n )
{
static const char* const name_of[]
{ "A", "AS_BF", "B", "C", "CS_BF", "D", "DS_EF", "E", "F", "FS_GF", "G", "GS_AF" } ;
return stm << name_of[n] ;
}
template < std::size_t N > using scale = std::array<note,N> ;
template < std::size_t N > std::ostream& operator<< ( std::ostream& stm, const scale<N>& notes )
{
// http://www.stroustrup.com/C++11FAQ.html#for
for( note n : notes ) stm << n << ' ' ;
return stm ;
}
using chromatic_scale = scale<12> ;
constexpr chromatic_scale standard_chromatic_scale // extra pair of braces to suppress a silly warning
{ { A, AS_BF, B, C, CS_DF, D, DS_EF, E, F, FS_GF, G, GS_AF } } ;
chromatic_scale keyed_chromatic_scale( note n )
{
chromatic_scale cs = standard_chromatic_scale ;
// http://en.cppreference.com/w/cpp/algorithm/rotate
std::rotate( std::begin(cs), std::begin(cs) + n, std::end(cs) ) ;
return cs ;
}
using standard_scale = scale<7> ;
using intervals = std::array<int,7> ;
// 2: tone interval, 1:semitone interval
constexpr intervals major_scale_intervals { { 2, 2, 1, 2, 2, 2 } } ;
standard_scale generate_scale( const chromatic_scale& cs, const intervals& steps )
{
standard_scale result {};
std::size_t pos = 0 ;
for( std::size_t i = 0 ; i < result.size() ; ++i )
{
result[i] = cs[ pos % cs.size() ] ; // *** note: modulo
pos += steps[i] ;
}
return result ;
}
standard_scale major_scale( note key )
{ return generate_scale( keyed_chromatic_scale(key), major_scale_intervals ) ; }
int main ()
{
for( note key : standard_chromatic_scale )
std::cout << key << " major: " << major_scale(key) << '\n' ;
}
|