From 8f5d8adf4862eaaa37cb441a224cd387e3c37fb1 Mon Sep 17 00:00:00 2001 From: Miika Alonen Date: Wed, 26 Apr 2023 21:14:21 +0300 Subject: [PATCH] Added pick and select for lists Pick: (1 2 3 4)?4 or (1 2 3 4)?(3 2) Select: (1 2 3 4)~2 or (1 2 3 4)~(2 3) --- ziffers/classes/items.py | 2 +- ziffers/classes/sequences.py | 49 +++++++++++++++++++++++++++++++++++- ziffers/defaults.py | 4 ++- ziffers/mapper.py | 2 +- ziffers/parser.py | 1 - ziffers/spec/ziffers.lark | 6 +++-- 6 files changed, 57 insertions(+), 7 deletions(-) diff --git a/ziffers/classes/items.py b/ziffers/classes/items.py index c3ada80..a4e405b 100644 --- a/ziffers/classes/items.py +++ b/ziffers/classes/items.py @@ -433,7 +433,7 @@ class RomanNumeral(Event): pitch_classes: list = field(default=None, init=False) inversions: int = field(default=None) evaluated_chord: Chord = None - + def set_notes(self, chord_notes: list[int]): """Set notes to roman numeral diff --git a/ziffers/classes/sequences.py b/ziffers/classes/sequences.py index 5b66b17..cd6b8f6 100644 --- a/ziffers/classes/sequences.py +++ b/ziffers/classes/sequences.py @@ -2,6 +2,7 @@ from dataclasses import dataclass, field, replace from itertools import product from math import floor +import random from types import LambdaType from copy import deepcopy import operator @@ -403,6 +404,47 @@ class ListOperation(Sequence): return flattened_list + def _pick_from_list(left, right, options): + """Pick random numbers from a list""" + if isinstance(left, Sequence): + left = _filter_operation(left, options) + + if isinstance(right, Sequence): + right = _filter_operation(right, options) + + if not isinstance(right, (list, Sequence)): + right = Sequence(values=[right]) + + result = [] + + for num in right.values: + for _ in range(num.get_value(options)): + result.append(random.choice(left.values)) + return flatten(result) + + + def _select_from_list(left, right, options): + """Select number of items from shuffled list""" + if isinstance(left, Sequence): + left = _filter_operation(left, options) + + if isinstance(right, Sequence): + right = _filter_operation(right, options) + + if not isinstance(right, (list, Sequence)): + right = Sequence(values=[right]) + + result = [] + left = left.values + + for num in right.values: + random.shuffle(left) + num = num.get_value(options) + new_list = [left[i % len(left)] for i in range(num)] + result += new_list + + return flatten(result) + def _vertical_arpeggio(left, right, options): """Vertical arpeggio operation, eg. (135)@(q 1 2 021)""" left = _filter_operation(left, options) @@ -537,8 +579,13 @@ class ListOperation(Sequence): left = _vertical_arpeggio(left, right, options) elif operation == "horizontal": left = _horizontal_arpeggio(left, right, options) - if operation == "zip": + elif operation == "zip": left = _cyclic_zip(left, right, options) + elif operation == "pick": + left = _pick_from_list(left, right, options) + elif operation == "select": + left = _select_from_list(left, right, options) + else: left = _python_operations(left, right, options) return left diff --git a/ziffers/defaults.py b/ziffers/defaults.py index e184796..92ca46b 100644 --- a/ziffers/defaults.py +++ b/ziffers/defaults.py @@ -62,7 +62,9 @@ OPERATORS = MappingProxyType({ ">>": operator.irshift, "@": "vertical", "#": "horizontal", - "<>": "zip" + "<>": "zip", + "?": "pick", + "~": "select" }) diff --git a/ziffers/mapper.py b/ziffers/mapper.py index 0443838..949329a 100644 --- a/ziffers/mapper.py +++ b/ziffers/mapper.py @@ -431,7 +431,7 @@ class ZiffersTransformer(Transformer): def lisp_operation(self, items): """Parse lisp like list operation""" op = items[0] - values = items[1:] + values = items[2] return LispOperation( operator=op, values=values, diff --git a/ziffers/parser.py b/ziffers/parser.py index 4fb12db..d0f083c 100644 --- a/ziffers/parser.py +++ b/ziffers/parser.py @@ -73,7 +73,6 @@ def zparse(expr: str, **opts) -> Ziffers: parsed.init_opts(opts) return parsed - # pylint: disable=invalid-name diff --git a/ziffers/spec/ziffers.lark b/ziffers/spec/ziffers.lark index 03466b9..bfb760f 100644 --- a/ziffers/spec/ziffers.lark +++ b/ziffers/spec/ziffers.lark @@ -56,8 +56,9 @@ right_op: list | number // Operators that work only on lists: | << >> list_operator: /(\||<<|>>|<>|#|@)(?=[(\d])/ + // /(\||<<|>>|<>|#|@)(?=[(\d])/ // Common operators that works with numbers 3+5 3-5 etc. - operator: /([\+\-\*\/%\&])/ + operator: /(\+|-|\*|\/|%|&|\?|~)/ // Euclidean cycles // TODO: Support randomization etc. @@ -66,7 +67,8 @@ ?euclid_operator: /<[0-9]+,[0-9]+(,[0-9])?>/ // Lisp like list operation - lisp_operation: "(" operator WS sequence ")" + lisp_operator: /([\+\-\*\/%\&])/ + lisp_operation: "(" lisp_operator WS sequence ")" // Subdivision subdivision: "[" subitems "]"