From 09553c539b8d790881d7c10cee419a042f33d864 Mon Sep 17 00:00:00 2001 From: Miika Alonen Date: Sun, 5 Feb 2023 16:54:00 +0200 Subject: [PATCH] Added tests for scale Added option to give intervals as scale name --- tests/test_parser.py | 2 +- tests/test_scale.py | 24 ++++++++++++++++++++++++ ziffers/scale.py | 11 ++++++----- 3 files changed, 31 insertions(+), 6 deletions(-) create mode 100644 tests/test_scale.py diff --git a/tests/test_parser.py b/tests/test_parser.py index 074a076..f06e7dd 100644 --- a/tests/test_parser.py +++ b/tests/test_parser.py @@ -43,4 +43,4 @@ def test_parsing_text(pattern: str): ], ) def test_pcs(pattern: str, expected: list): - assert parse_expression(pattern).pcs == expected \ No newline at end of file + assert parse_expression(pattern).pcs() == expected \ No newline at end of file diff --git a/tests/test_scale.py b/tests/test_scale.py new file mode 100644 index 0000000..4571f9b --- /dev/null +++ b/tests/test_scale.py @@ -0,0 +1,24 @@ +from ziffers import scale +import pytest + +@pytest.mark.parametrize( + "name,expected", + [ + ("C4", 60), + ("A1", 33), + ("Bb3", 58), + ("C#1", 25), + ("foo", 60), + ], +) +def test_notenames(name: str, expected: int): + assert scale.note_to_midi(name) == expected + +@pytest.mark.parametrize( + "pcs,expected", + [ + (list(range(-9,10)), [45, 47, 48, 50, 52, 53, 55, 57, 59, 60, 62, 64, 65, 67, 69, 71, 72, 74, 76]), + ], +) +def test_note_to_midi(pcs: str, expected: int): + assert [scale.note_from_pc(root=60, pitch_class=val, intervals="Ionian") for val in pcs] == expected diff --git a/ziffers/scale.py b/ziffers/scale.py index ae94049..fa9bd2b 100644 --- a/ziffers/scale.py +++ b/ziffers/scale.py @@ -1515,14 +1515,13 @@ def note_to_midi(name: str) -> int: ''' Parse note name to midi ''' items = re.match(r"^([a-gA-G])([#bs])?([1-9])?$",name) if items==None: - raise ValueError("Invalid note name: "+name) + return 60 values = items.groups() octave = int(values[2]) if values[2] else 4 modifier = modifiers[values[1]] if values[1] else 0 interval = note_to_interval[values[0].capitalize()] return 12 + octave * 12 + interval + modifier - def get_scale(name: str) -> list: """Get a scale from the global scale list""" scale = SCALES.get( @@ -1534,19 +1533,21 @@ def get_scale(name: str) -> list: def note_from_pc( root: int|str, pitch_class: int, - intervals: list[int|float], + intervals: str | list[int|float], cents: bool = False, octave: int = 0, - addition: int = 0 + modifier: int = 0 ) -> int: """Resolve a pitch class into a note from a scale""" if type(root)==str: root = note_to_midi(root) if cents: intervals = list(map(lambda x: x / 100), intervals) + if type(intervals) == str: + intervals = get_scale(intervals) interval_sum = sum(intervals[0:pitch_class]) note = (root + interval_sum if pitch_class >= 0 else root - interval_sum) - return note + octave*sum(intervals) + addition + return note + octave*sum(intervals) + modifier if __name__ == "__main__":