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
|
from __future__ import annotations
class Scale:
STEPS = {
"major": [2, 2, 1, 2, 2, 2, 1],
"min nat": [2, 1, 2, 2, 1, 2, 2],
"min harm": [2, 1, 2, 2, 1, 3, 1],
"min mel": [2, 1, 2, 2, 2, 2, 1],
"min hung": [2, 1, 3, 1, 1, 3, 1],
"whole": [2, 2, 2, 2, 2, 2],
"penta": [2, 2, 3, 2, 3],
}
# LABELS = {
# 'english': 'C C# D D# E F F# G G# A A# B'.split(' '),
# 'german': 'C C# D D# E F F# G G# A A# H'.split(' '),
# 'sol': 'do do# re re# mi fa fa# sol sol# la la# si'.split(' '),
# }
LABELS = "C C# D D# E F F# G G# A A# B".split(" ")
root: int
name: str
notes: list[int]
size: int
def __init__(self, root: int, steps: list[int], name: str):
self.root = root
self.name = name
self.notes = [sum(steps[:i]) for i in range(len(steps))]
self.size = sum(steps)
def is_in_scale(self, pitch: int) -> Union[bool, Literal["core"]]:
relative_pitch = (pitch - self.root) % self.size
if relative_pitch not in self.notes:
return False
if self.root <= pitch < self.root + self.size:
return "core"
return True
def label(self, pitch, octave=False):
off = pitch % self.size
oct = ""
if octave:
oct = str(self.root // self.size)
return self.LABELS[off] + oct
def format(self):
oct = self.root // self.size
off = self.root % self.size
return "SCALE: {} {} {}".format(
self.LABELS[off],
oct,
self.name,
)
|