aboutsummaryrefslogtreecommitdiffstats
path: root/src/scale.c
blob: 197959ece997b6fc48c92f133f363b89117a0cb9 (plain)
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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
typedef enum Scales {
    SCALE_CHRM,
    SCALE_MAJR,
    SCALE_MINR,
    SCALE_PMAJ,
    SCALE_PMIN,
    SCALE_BLUE,
    SCALE_DORI,
    SCALE_PHYR,
    SCALE_LYDI,
    SCALE_MIXO,
    SCALE_LOCR,
    SCALE_PERS,
    SCALE_HMIN,
    SCALE_IWAT,
    SCALE_INSN,
    SCALE_HIRA,
    SCALE_NUM,
} Scales;

int current_scale = SCALE_CHRM;
int current_scale_root = 0;

char *scale_short[] = {
    "CHRM",
    "MAJR",
    "MINR",
    "PMAJ",
    "PMIN",
    "BLUE",
    "DORI",
    "PHYR",
    "LYDI",
    "MIXO",
    "LOCR",
    "PERS",
    "HMIN",
    "IWAT",
    "INSN",
    "HIRA",
};

char *scale_long[] = {
    "CHROMATIC",
    "MAJOR",
    "MINOR",
    "PENTATONIC MAJOR",
    "PENTATONIC MINOR",
    "BLUES",
    "DORIAN",
    "PHYRGIAN",
    "LYDIAN",
    "MIXOLYDIAN",
    "LOCRIAN",
    "PERSIAN",
    "HUNGARIAN MINOR",
    "IWATO",
    "IN-SEN",
    "HIRAJOSHI",
};

typedef u8 Scale[12];
Scale scales[] = {
//   1  b2 2  b3 3  4 b5  5 b6  6 b7  7   <- Major
    {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, // CHRM
    {1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1}, // MAJR
    {1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0}, // MINR
    {1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0}, // PMAJ
    {1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0}, // PMIN
    {1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0}, // BLUE
    {1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0}, // DORI
    {1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0}, // PHYR
    {1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1}, // LYDI
    {1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0}, // MIXO
    {1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0}, // LOCR
    {1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1}, // PERS
    {1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1}, // HMIN
    {1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0}, // IWAT
    {1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0}, // INSN
    {1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0}, // HIRA
};

s32
scale_note(s32 current, s32 inc) {
    if (inc > 1 || inc < -1) {
        return CLAMP(current + inc, (s32)NOTE_C_2, (s32)NOTE_C_8 - 1);
    }
    s32 pos = current % 12;
    s32 offset = 0;
    for (int i = 1; i <= 12; i++) {
        s32 k = (pos - current_scale_root + i * inc) % 12;
        if (k < 0) {
            k *= -1;
            k = 12 - k;
        }
        offset += inc;
        if (scales[current_scale][k] == 1) {
            break;
        }
    }
    return CLAMP(current + offset, (s32)NOTE_C_2, (s32)NOTE_C_8 - 1);
}