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); }