diff --git a/ziffers/classes/items.py b/ziffers/classes/items.py index 4c6c595..924fc6c 100644 --- a/ziffers/classes/items.py +++ b/ziffers/classes/items.py @@ -479,6 +479,13 @@ class Variable(Event): name: str +@dataclass(kw_only=True) +class Sample(Event): + """Class for samples""" + + name: str + + @dataclass(kw_only=True) class VariableList(Item): """Class for using variables""" diff --git a/ziffers/classes/sequences.py b/ziffers/classes/sequences.py index de5324d..143a808 100644 --- a/ziffers/classes/sequences.py +++ b/ziffers/classes/sequences.py @@ -29,8 +29,10 @@ from .items import ( Function, Modification, Whitespace, + Sample, ) + # TODO: Could be refactored to each class? def resolve_item(item: Meta, options: dict): """Resolve cyclic value""" @@ -38,7 +40,7 @@ def resolve_item(item: Meta, options: dict): if isinstance(item, ListOperation): yield from item.evaluate(options) elif isinstance(item, (RepeatedSequence, RepeatedListSequence)): - yield from item.resolve_repeat(options) + yield from item.resolve_repeat(options) elif isinstance(item, Subdivision): item.evaluate_values(options) yield item @@ -58,7 +60,17 @@ def resolve_item(item: Meta, options: dict): if item.name in options: opt_item = options[item.name] if isinstance(opt_item, LambdaType): - yield Function(run=opt_item, text=item.text, kwargs=options) + yield Function( + run=opt_item, + text=item.text, + kwargs=(options | item.local_options), + ) + elif isinstance(opt_item, str): + yield Sample( + name=opt_item, + text=item.text, + kwargs=(options | item.local_options), + ) variable = deepcopy(opt_item) yield from resolve_item(variable, options) elif isinstance(item, VariableList): @@ -68,7 +80,19 @@ def resolve_item(item: Meta, options: dict): opt_item = options[var.name] if isinstance(opt_item, LambdaType): seqlist.append( - Function(run=opt_item, text=var.text, kwargs=options) + Function( + run=opt_item, + text=var.text, + kwargs=(options | var.local_options), + ) + ) + elif isinstance(opt_item, str): + seqlist.append( + Sample( + name=opt_item, + text=var.text, + kwargs=(options | var.local_options), + ) ) elif isinstance(opt_item, Sequence): seqlist.append(opt_item) @@ -87,6 +111,7 @@ def resolve_item(item: Meta, options: dict): elif isinstance(item, Meta): # Filters whitespace yield update_item(item, options) + def resolve_integer_value(item, options): """Helper for resolving integer value of different types""" while isinstance(item, Cyclic): @@ -97,6 +122,7 @@ def resolve_integer_value(item, options): return item.get_value(options) return item + def update_item(item, options): """Update or create new pitch""" if set(("key", "scale")) <= options.keys(): @@ -116,12 +142,14 @@ def update_item(item, options): item = item.evaluate_chord(options) return item + def euclidean_items(euclid: Item, options: dict): """Loops values from generated euclidean sequence""" euclid.evaluate(options) for item in euclid.evaluated_values: yield from resolve_item(item, options) + def update_modifications(current: Item, options: dict) -> dict: """Update options based on current item""" if isinstance(current, (OctaveChange, DurationChange)): @@ -132,6 +160,7 @@ def update_modifications(current: Item, options: dict) -> dict: else: # Create value if not existing options[current.key] = current.value + def create_pitch(current: Item, options: dict) -> Pitch: """Create pitch based on values and options""" @@ -249,6 +278,7 @@ class Sequence(Meta): @dataclass(kw_only=True) class PolyphonicSequence: """Class for polyphonic sequence""" + values: list @@ -357,9 +387,9 @@ class ListOperation(Sequence): """Vertical arpeggio operation, eg. (135)@(q 1 2 021)""" left = _filter_operation(left, options) right = _filter_operation(right, options) - if not isinstance(left,list): + if not isinstance(left, list): left = list(left.evaluate_tree(options)) - if not isinstance(right,list): + if not isinstance(right, list): right = list(right.evaluate_tree(options)) arp_items = [] diff --git a/ziffers/mapper.py b/ziffers/mapper.py index 4a92cb8..defa234 100644 --- a/ziffers/mapper.py +++ b/ziffers/mapper.py @@ -337,8 +337,15 @@ class ZiffersTransformer(Transformer): return items[0].value def variable(self, items): + if len(items)>1: + prefixes = sum_dict(items[0:-1]) + text_prefix = prefixes.pop("text") + return Variable(name=items[-1], text=text_prefix+items[-1], local_options=prefixes) + return Variable(name=items[0], text=items[0]) + + def variable_char(self, items): """Return parsed variable name""" - return Variable(name=items[0].value, text=items[0].value) + return items[0].value #Variable(name=items[0].value, text=items[0].value) def variablelist(self, items): """Return list of variables""" diff --git a/ziffers/spec/ziffers.lark b/ziffers/spec/ziffers.lark index 3132377..0066d26 100644 --- a/ziffers/spec/ziffers.lark +++ b/ziffers/spec/ziffers.lark @@ -16,7 +16,8 @@ // Variable assignment assignment: variable ass_op (list | pitch_class | random_integer | random_pitch | cycle | list_op | repeat_item) ass_op: /[=~]/ - variable: /[A-Z]/ + variable: prefix* variable_char + variable_char: /[A-Z]/ variablelist: variable variable+