from typing import List, Optional
from .constants import NOTE_VAL_DICT, SCALE_VAL_DICT
[docs]
def note_to_val(note: str) -> int:
"""Get index value of a note
>>> note_to_val("C")
0
>>> note_to_val("B")
11
"""
if note not in NOTE_VAL_DICT:
raise ValueError(f"Unknown note {note}")
return NOTE_VAL_DICT[note]
[docs]
def val_to_note(
val: int,
scale: str = "C",
index: Optional[int] = None,
quality: Optional[str] = None,
) -> str:
"""Return note by index in a scale
>>> val_to_note(0)
"C"
>>> val_to_note(11, "D")
"D#"
"""
val %= 12
if index is None or quality is None:
return SCALE_VAL_DICT[scale][val]
# NOTE: Is there a better way to implement this?
is_flatted = (
(quality.startswith("dim") and index == 1)
or (
(
quality.find("b5") >= 1
or quality.find("-5") >= 1
or quality.startswith("dim")
)
and index == 2
)
or ((quality == "dim7") and index == 3)
or ((quality.find("b9") >= 1 or quality.find("-9") >= 1) and index == 4)
# TODO: Remove special logic below for Gm
or (
val == 10
and index == 1
and (
(quality.startswith("m") and not quality.startswith("maj"))
or quality.startswith("dim")
)
)
)
if is_flatted:
temp = SCALE_VAL_DICT[scale][(val + 1) % 12]
return f"{temp}b".replace("#b", "")
is_sharped = (
(
(quality.find("#5") >= 1 or quality.find("+5") >= 1 or quality == "aug")
and index == 2
)
or ((quality.find("#9") >= 1 or quality.find("+9") >= 1) and index == 4)
or ((quality.find("7#11") >= 0 or quality.find("7+11") >= 0) and index == 5)
or ((quality in ("13#11", "13+11")) and index == 5)
or ((quality.find("9#11") >= 0 or quality.find("9+11") >= 0) and index == 6)
)
if is_sharped:
temp = SCALE_VAL_DICT[scale][(val - 1) % 12]
return f"{temp}#".replace("b#", "")
return SCALE_VAL_DICT[scale][val]
[docs]
def transpose_note(note: str, transpose: int, scale: str = "C") -> str:
"""Transpose a note
>>> transpose_note("C", 1)
"Db"
>>> transpose_note("D", 4, "A")
"F#"
"""
val = note_to_val(note)
val += transpose
return val_to_note(val, scale)
[docs]
def display_appended(appended: List[str]) -> str:
# TODO: Implement this
return ""
[docs]
def display_on(on_note: str) -> str:
if on_note:
return f"/{on_note}"
return ""