Added repeats

This commit is contained in:
2023-02-04 21:12:13 +02:00
parent 6597ca3f17
commit 26d3825ffb
3 changed files with 84 additions and 39 deletions

View File

@ -16,6 +16,10 @@ class Item(Meta):
''' Class for all Ziffers text based items ''' ''' Class for all Ziffers text based items '''
text: str text: str
@dataclass
class Whitespace(Item):
''' Class for whitespace '''
@dataclass @dataclass
class DurationChange(Item): class DurationChange(Item):
''' Class for changing duration ''' ''' Class for changing duration '''
@ -73,8 +77,8 @@ class dataclass_property(property): # pylint: disable=invalid-name
@dataclass @dataclass
class Sequence(Meta): class Sequence(Meta):
''' Class for sequences of items''' ''' Class for sequences of items'''
values: list values: list[Item]
text: str = None text: str = field(init=False)
_text: str = field(default=None, init=False, repr=False) _text: str = field(default=None, init=False, repr=False)
@dataclass_property @dataclass_property
@ -85,23 +89,11 @@ class Sequence(Meta):
def text(self, text: str) -> None: def text(self, text: str) -> None:
self._text = text self._text = text
wrapper: str = None wrap_start: str = field(default=None, repr=False)
_wrapper: str = field(default=None, init=False, repr=False) wrap_end: str = field(default=None, repr=False)
@dataclass_property
def wrapper(self) -> str:
return self._wrapper
@wrapper.setter
def wrapper(self, wrapper: str) -> None:
self._wrapper = wrapper
if self.text != None:
self.text = self.wrapper[0] + self.text + self.wrapper[1]
def __post_init__(self): def __post_init__(self):
self.text = self.collect_text() self.text = self.collect_text()
if self.text != None and self.wrapper != None:
self.text = self.wrapper[0] + self.text + self.wrapper[1]
def update_values(self, new_values): def update_values(self, new_values):
''' Update value attributes from dict ''' ''' Update value attributes from dict '''
@ -111,8 +103,13 @@ class Sequence(Meta):
setattr(obj, key, value) setattr(obj, key, value)
def collect_text(self) -> str: def collect_text(self) -> str:
return "".join([val.text for val in self.values]) text = "".join([val.text for val in self.values])
if self.wrap_start != None:
text = self.wrap_start + text
if self.wrap_end != None:
text = text + self.wrap_end
return text
def pcs(self) -> list[int]: def pcs(self) -> list[int]:
return [val.pc for val in self.values if type(val) is Pitch] return [val.pc for val in self.values if type(val) is Pitch]
@ -125,12 +122,15 @@ class Sequence(Meta):
@dataclass @dataclass
class ListSequence(Sequence): class ListSequence(Sequence):
''' Class for Ziffers list sequences ''' ''' Class for Ziffers list sequences '''
prefix: dict = None wrap_start: str = field(default="(", repr=False)
values: list = None wrap_end: str = field(default=")", repr=False)
def __init__(self):
super.__init__() @dataclass
if self.prefix!=None: class RepeatedListSequence(Sequence):
self.update(self.prefix) ''' Class for Ziffers list sequences '''
repeats: Item = None
wrap_start: str = field(default="(:", repr=False)
wrap_end: str = field(default=":)", repr=False)
@dataclass @dataclass
class Subdivision(Item): class Subdivision(Item):
@ -141,6 +141,9 @@ class Subdivision(Item):
class Cyclic(Sequence): class Cyclic(Sequence):
''' Class for cyclic sequences''' ''' Class for cyclic sequences'''
cycle: int = 0 cycle: int = 0
wrap_start: str = field(default="<", repr=False)
wrap_end: str = field(default=">", repr=False)
def __post_init__(self): def __post_init__(self):
super().__post_init__() super().__post_init__()
# TODO: Do spaced need to be filtered out? # TODO: Do spaced need to be filtered out?
@ -189,6 +192,8 @@ class Operation(Item):
class Eval(Sequence): class Eval(Sequence):
''' Class for evaluation notation ''' ''' Class for evaluation notation '''
result: ... = None result: ... = None
wrap_start: str = field(default="{", repr=False)
wrap_end: str = field(default="}", repr=False)
def __post_init__(self): def __post_init__(self):
super().__post_init__() super().__post_init__()
self.result = eval(self.text) self.result = eval(self.text)
@ -210,4 +215,12 @@ class Euclid(Item):
length: int length: int
onset: list onset: list
offset: list = None offset: list = None
rotate: int = None rotate: int = None
@dataclass
class RepeatedSequence(Sequence):
''' Class for repeats '''
repeats: Item = None
wrap_start: str = field(default="[:", repr=False)
wrap_end: str = field(default=":]", repr=False)

View File

@ -6,8 +6,11 @@ import operator
class ZiffersTransformer(Transformer): class ZiffersTransformer(Transformer):
def start(self,items):
return Sequence(values=items[0])
def sequence(self,items): def sequence(self,items):
return Sequence(values=flatten(items)) return flatten(items)
def random_integer(self,s): def random_integer(self,s):
val = s[0][1:-1].split(",") val = s[0][1:-1].split(",")
@ -18,8 +21,8 @@ class ZiffersTransformer(Transformer):
return Range(start=val[0],end=val[1],text=s[0]) return Range(start=val[0],end=val[1],text=s[0])
def cycle(self, items): def cycle(self, items):
values = items[0].values values = items[0]
return Cyclic(values=values, wrapper="<>") return Cyclic(values=values)
def pc(self, s): def pc(self, s):
if(len(s)>1): if(len(s)>1):
@ -95,7 +98,7 @@ class ZiffersTransformer(Transformer):
return chardur return chardur
def WS(self,s): def WS(self,s):
return Item(text=s[0]) return Whitespace(text=s[0])
def subdivision(self,items): def subdivision(self,items):
values = flatten(items[0]) values = flatten(items[0])
@ -108,7 +111,7 @@ class ZiffersTransformer(Transformer):
def eval(self,s): def eval(self,s):
val = s[0] val = s[0]
return Eval(values=val,wrapper="{}") return Eval(values=val)
def operation(self,s): def operation(self,s):
return s return s
@ -122,14 +125,28 @@ class ZiffersTransformer(Transformer):
def list(self,items): def list(self,items):
if len(items)>1: if len(items)>1:
prefixes = sum_dict(items[0:-1]) prefixes = sum_dict(items[0:-1])
seq = items[-1] values = items[-1]
seq.wrapper = "()" seq = ListSequence(values=values,wrap_start=prefixes["text"]+"(")
seq.text = prefixes["text"] + seq.text
seq.update_values(prefixes) seq.update_values(prefixes)
return seq return seq
else: else:
seq = items[0] seq = ListSequence(values=items[0])
seq.wrapper = "()" return seq
def repeated_list(self,items):
if len(items)>2:
prefixes = sum_dict(items[0:-2]) # If there are prefixes
if items[-1]!=None:
seq = RepeatedListSequence(values=items[-2],repeats=items[-1],wrap_end=":"+items[-1].text+")")
else:
seq = RepeatedListSequence(values=items[-2],repeats=Integer(text='1', value=1))
seq.update_values(prefixes)
return seq
else:
if items[-1]!=None:
seq = RepeatedListSequence(values=items[-2],repeats=items[-1],wrap_end=":"+items[-1].text+")")
else:
seq = RepeatedListSequence(values=items[-2],repeats=Integer(text='1', value=1))
return seq return seq
def SIGNED_NUMBER(self, s): def SIGNED_NUMBER(self, s):
@ -139,6 +156,9 @@ class ZiffersTransformer(Transformer):
def number(self,s): def number(self,s):
return s return s
def cyclic_number(self,s):
return Cyclic(values=s)
def lisp_operation(self,s): def lisp_operation(self,s):
op = s[0] op = s[0]
values = s[1:] values = s[1:]
@ -167,4 +187,10 @@ class ZiffersTransformer(Transformer):
return Euclid(**init) return Euclid(**init)
def euclid_operator(self,s): def euclid_operator(self,s):
return s.value return s.value
def repeat(self,s):
if s[-1]!=None:
return RepeatedSequence(values=s[0],repeats=s[-1],wrap_end=":"+s[-1].text+"]")
else:
return RepeatedSequence(values=s[0],repeats=Integer(value=1,text='1'))

View File

@ -1,6 +1,6 @@
// Root for the rules // Root for the rules
?root: sequence ?root: sequence -> start
sequence: (pc | dur_change | oct_mod | oct_change | WS | chord | cycle | random_integer | random_pitch | random_percent | range | list | lisp_operation | list_op | subdivision | eval | euclid)* sequence: (pc | dur_change | oct_mod | oct_change | WS | chord | cycle | random_integer | random_pitch | random_percent | range | list | repeated_list | lisp_operation | list_op | subdivision | eval | euclid | repeat)*
// Pitch classes // Pitch classes
pc: prefix* pitch pc: prefix* pitch
@ -14,15 +14,21 @@
chord: pc pc+ chord: pc pc+
// Valid as integer // Valid as integer
?number: SIGNED_NUMBER | random_integer ?number: SIGNED_NUMBER | random_integer | cyclic_number
cyclic_number: "<" number (WS number)* ">"
// Repeats
repeat: "[:" sequence ":" [number] "]"
// List // List
list: prefix* "(" sequence ")" list: prefix* "(" sequence ")"
repeated_list: prefix* "(:" sequence ":" [number] ")"
// Right recursive list operation // Right recursive list operation
list_op: list (operator (list | number))+ list_op: list (operator (list | number))+
operator: /([\+\-\*\/%]|<<|>>)/ operator: /([\+\-\*\/%]|<<|>>)/
// Euclidean cycles
euclid: list euclid_operator list? euclid: list euclid_operator list?
?euclid_operator: /<[0-9]+,[0-9]+(,[0-9])?>/ ?euclid_operator: /<[0-9]+,[0-9]+(,[0-9])?>/