PiCoGen / sheetsage /theory /basic.py
Vansh Chugh
vendor jukebox+sheetsage source and recovered weights, use_jukebox=True
ff7b988
Raw
History Blame Contribute Delete
3.53 kB
_HUMAN_PN_TO_PC = {
"C": 0,
"D": 2,
"E": 4,
"F": 5,
"G": 7,
"A": 9,
"B": 11,
}
_PC_TO_FLAT_HUMAN_PN = "C Db D Eb E F Gb G Ab A Bb B".split()
_PC_TO_SHARP_HUMAN_PN = "C C# D D# E F F# G G# A A# B".split()
class PitchClass(int):
def __new__(cls, pc):
if not isinstance(pc, int):
raise TypeError()
if pc < 0 or pc >= 12:
raise ValueError()
return super().__new__(cls, pc)
def as_human_pitch_name(self, enharmonics="b"):
if enharmonics == "b":
d = _PC_TO_FLAT_HUMAN_PN
elif enharmonics == "#":
d = _PC_TO_SHARP_HUMAN_PN
else:
raise ValueError()
return HumanPitchName(d[self])
def as_lily_pitch_name(self, enharmonics="es"):
if enharmonics == "es":
enharmonics = "b"
elif enharmonics == "is":
enharmonics = "#"
else:
raise ValueError()
return self.as_human_pitch_name(enharmonics=enharmonics).as_lily_pitch_name()
class PitchInterval(int):
def __new__(cls, pi):
if not isinstance(pi, int):
raise TypeError()
return super().__new__(cls, pi)
class HumanPitchName(str):
def __new__(cls, pn):
if not isinstance(pn, str):
raise TypeError()
if len(pn) == 0:
raise ValueError()
if pn[0] not in _HUMAN_PN_TO_PC:
raise ValueError()
accidentals = list(pn[1:])
if any(a not in ["b", "#"] for a in accidentals):
raise ValueError()
if len(set(accidentals)) > 1:
raise ValueError()
if len(accidentals) > 2:
raise ValueError()
return super().__new__(cls, pn)
def as_pitch_class(self):
pc = _HUMAN_PN_TO_PC[self[0]]
accidental = 0
for c in self[1:]:
if c == "b":
accidental -= 1
elif c == "#":
accidental += 1
else:
assert False
return PitchClass((pc + accidental) % 12)
def as_lily_pitch_name(self):
pn = self[0].lower()
for c in self[1:]:
if c == "b":
pn += "es"
elif c == "#":
pn += "is"
else:
assert False
return LilyPitchName(pn)
class LilyPitchName(str):
def __new__(cls, pn):
if not isinstance(pn, str):
raise TypeError()
if len(pn) == 0:
raise ValueError()
if pn.lower() != pn:
raise ValueError()
if pn[0].upper() not in _HUMAN_PN_TO_PC:
raise ValueError()
accidentals = pn[1:]
if len(accidentals) % 2 != 0:
raise ValueError()
accidentals = [accidentals[i : i + 2] for i in range(0, len(accidentals), 2)]
if any(a not in ["es", "is"] for a in accidentals):
raise ValueError()
if len(set(accidentals)) > 1:
raise ValueError()
if len(accidentals) > 3:
raise ValueError()
return super().__new__(cls, pn)
def as_pitch_class(self):
return self.as_human_pitch_name().as_pitch_class()
def as_human_pitch_name(self):
pn = self[0].upper()
for i in range(1, len(self), 2):
if self[i : i + 2] == "es":
pn += "b"
elif self[i : i + 2] == "is":
pn += "#"
else:
assert False
return HumanPitchName(pn)