Degree based notation
Added parameter for degree based notation. Using degrees=True integers are interpreted as degrees and 0=Rest.
This commit is contained in:
@ -16,7 +16,8 @@ def test_can_parse():
|
|||||||
"q 2 <3 343>",
|
"q 2 <3 343>",
|
||||||
"q (2 <3 343 (3 4)>)",
|
"q (2 <3 343 (3 4)>)",
|
||||||
"? 1 2",
|
"? 1 2",
|
||||||
"(? 2 ? 4)+(1,4)"
|
"(? 2 ? 4)+(1,4)",
|
||||||
|
"(1 2 <2 3>)+(0 1 2)"
|
||||||
]
|
]
|
||||||
results = []
|
results = []
|
||||||
for expression in expressions:
|
for expression in expressions:
|
||||||
@ -43,7 +44,6 @@ def test_can_parse():
|
|||||||
def test_parsing_text(pattern: str):
|
def test_parsing_text(pattern: str):
|
||||||
assert zparse(pattern).text == pattern
|
assert zparse(pattern).text == pattern
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"pattern,expected",
|
"pattern,expected",
|
||||||
[
|
[
|
||||||
@ -159,6 +159,15 @@ def test_rest(pattern: str, expected: list):
|
|||||||
def test_ranges(pattern: str, expected: list):
|
def test_ranges(pattern: str, expected: list):
|
||||||
assert get_items(zparse(pattern),len(expected)*2,"note") == expected*2
|
assert get_items(zparse(pattern),len(expected)*2,"note") == expected*2
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"pattern,expected",
|
||||||
|
[
|
||||||
|
("0 1 2 3", [None, 60, 62, 64])
|
||||||
|
]
|
||||||
|
)
|
||||||
|
def test_degree_notation(pattern: str, expected: list):
|
||||||
|
assert get_items(zparse(pattern, degrees=True),len(expected)*2,"note") == expected*2
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"pattern,expected",
|
"pattern,expected",
|
||||||
[
|
[
|
||||||
|
|||||||
@ -198,6 +198,7 @@ class Pitch(Event):
|
|||||||
key: str = field(default=None)
|
key: str = field(default=None)
|
||||||
scale: str | list = field(default=None)
|
scale: str | list = field(default=None)
|
||||||
freq: float = field(default=None)
|
freq: float = field(default=None)
|
||||||
|
degrees: bool = field(default=None)
|
||||||
|
|
||||||
def __post_init__(self):
|
def __post_init__(self):
|
||||||
super().__post_init__()
|
super().__post_init__()
|
||||||
@ -246,6 +247,7 @@ class Pitch(Event):
|
|||||||
intervals=self.scale,
|
intervals=self.scale,
|
||||||
modifier=self.modifier if self.modifier is not None else 0,
|
modifier=self.modifier if self.modifier is not None else 0,
|
||||||
octave=self.octave if self.octave is not None else 0,
|
octave=self.octave if self.octave is not None else 0,
|
||||||
|
degrees=self.degrees
|
||||||
)
|
)
|
||||||
self.pitch_bend = pitch_bend
|
self.pitch_bend = pitch_bend
|
||||||
self.freq = midi_to_freq(note)
|
self.freq = midi_to_freq(note)
|
||||||
@ -598,6 +600,8 @@ class Cyclic(Item):
|
|||||||
"""Get the value for the current cycle"""
|
"""Get the value for the current cycle"""
|
||||||
value = self.values[self.cycle % len(self.values)]
|
value = self.values[self.cycle % len(self.values)]
|
||||||
self.cycle += 1
|
self.cycle += 1
|
||||||
|
if options:
|
||||||
|
value.update_options(options)
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -124,6 +124,8 @@ def resolve_item(item: Meta, options: dict):
|
|||||||
update_modifications(item, options)
|
update_modifications(item, options)
|
||||||
elif isinstance(item, Measure):
|
elif isinstance(item, Measure):
|
||||||
item.reset_options(options)
|
item.reset_options(options)
|
||||||
|
elif options["degrees"] is True and isinstance(item, Pitch) and item.pitch_class is 0:
|
||||||
|
yield Rest(text="r", kwargs=options)
|
||||||
elif isinstance(item, Meta): # Filters whitespace
|
elif isinstance(item, Meta): # Filters whitespace
|
||||||
yield update_item(item, options)
|
yield update_item(item, options)
|
||||||
|
|
||||||
@ -208,6 +210,7 @@ def create_pitch(current: Item, options: dict) -> Pitch:
|
|||||||
intervals=merged_options["scale"],
|
intervals=merged_options["scale"],
|
||||||
modifier=c_modifier,
|
modifier=c_modifier,
|
||||||
octave=c_octave,
|
octave=c_octave,
|
||||||
|
degrees=merged_options["degrees"]
|
||||||
)
|
)
|
||||||
new_pitch = Pitch(
|
new_pitch = Pitch(
|
||||||
pitch_class=current_value,
|
pitch_class=current_value,
|
||||||
@ -382,7 +385,7 @@ class ListOperation(Sequence):
|
|||||||
else:
|
else:
|
||||||
flattened_list.append(_filter_operation(item, options))
|
flattened_list.append(_filter_operation(item, options))
|
||||||
elif isinstance(item, Cyclic):
|
elif isinstance(item, Cyclic):
|
||||||
value = item.get_value()
|
value = item.get_value(options)
|
||||||
if isinstance(value, Sequence):
|
if isinstance(value, Sequence):
|
||||||
flattened_list.extend(_filter_operation(value, options))
|
flattened_list.extend(_filter_operation(value, options))
|
||||||
elif isinstance(value, (Event, RandomInteger, Integer)):
|
elif isinstance(value, (Event, RandomInteger, Integer)):
|
||||||
|
|||||||
@ -47,7 +47,8 @@ DEFAULT_OPTIONS = MappingProxyType({
|
|||||||
"duration": 0.25,
|
"duration": 0.25,
|
||||||
"key": "C4",
|
"key": "C4",
|
||||||
"scale": "IONIAN",
|
"scale": "IONIAN",
|
||||||
"measure": 0
|
"measure": 0,
|
||||||
|
"degrees": False
|
||||||
})
|
})
|
||||||
|
|
||||||
OPERATORS = MappingProxyType({
|
OPERATORS = MappingProxyType({
|
||||||
|
|||||||
@ -149,7 +149,6 @@ def get_scale_length(scale: str) -> int:
|
|||||||
|
|
||||||
return len(SCALES.get(scale.lower().capitalize(), SCALES["Ionian"]))
|
return len(SCALES.get(scale.lower().capitalize(), SCALES["Ionian"]))
|
||||||
|
|
||||||
|
|
||||||
# pylint: disable=locally-disabled, too-many-arguments
|
# pylint: disable=locally-disabled, too-many-arguments
|
||||||
def note_from_pc(
|
def note_from_pc(
|
||||||
root: int | str,
|
root: int | str,
|
||||||
@ -157,6 +156,7 @@ def note_from_pc(
|
|||||||
intervals: str | tuple[int | float],
|
intervals: str | tuple[int | float],
|
||||||
octave: int = 0,
|
octave: int = 0,
|
||||||
modifier: int = 0,
|
modifier: int = 0,
|
||||||
|
degrees: bool = False
|
||||||
) -> int:
|
) -> int:
|
||||||
"""Resolve a pitch class into a note from a scale
|
"""Resolve a pitch class into a note from a scale
|
||||||
|
|
||||||
@ -173,6 +173,7 @@ def note_from_pc(
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
# Initialization
|
# Initialization
|
||||||
|
pitch_class = pitch_class-1 if degrees and pitch_class>0 else pitch_class
|
||||||
root = note_name_to_midi(root) if isinstance(root, str) else root
|
root = note_name_to_midi(root) if isinstance(root, str) else root
|
||||||
intervals = get_scale(intervals) if isinstance(intervals, str) else intervals
|
intervals = get_scale(intervals) if isinstance(intervals, str) else intervals
|
||||||
scale_length = len(intervals)
|
scale_length = len(intervals)
|
||||||
|
|||||||
Reference in New Issue
Block a user