import math import json from padmanager import PadManager class InputAction(list): def __init__(self, js): super().__init__(js) def json(self): return self class InputActionList(): def __init__(self, js): self.actions=[] if len(js)>0: if isinstance(js[0], str): self.actions.append(InputAction(js)) else: for k in js: self.actions.append(k) def json(self): x=[] for k in self.actions: x.append(k) return x class InputDefinition: def __init__(self, js): self.type=js["type"] self.actions={} for k in js["actions"]: self.actions[k]=InputActionList(js["actions"][k]) self.shape=js["shape"] if "shape" in js else "" def json(self): actions={} for k in self.actions: actions[k]=self.actions[k].json() return { "type" : self.type, "actions" : self.actions, "shape" : self.shape } class Pad: def __init__(self, js): self.name=js["name"] self.width=js["width"] self.height=js["height"] self.ports=js["ports"] self.inputs={} for k in js["inputs"]: self.inputs[k]=InputDefinition(js["inputs"][k]) self.matrix=[] for i in range(self.width*self.height): self.matrix.append(None) for i in range(self.width*self.height): obj=js["matrix"][i] if obj: self.matrix[i]=self.inputs[obj["type"]] class Operation: def __init__(self, type, js=None): pass def json(self): raise NotImplementedError @staticmethod def parse(js): cl = CLASSES[js["type"]] return cl(js) class DropOperation(Operation): TYPE="DROP" def __init__(self, js): super().__init__(js) self.type=DropOperation.TYPE def json(self): return {"type" : DropOperation.TYPE} @staticmethod def new(): return DropOperation(None) def __str__(self): return "Drop()" class ReorderOperation(Operation): TYPE="REORDER" def __init__(self, js): super().__init__(js) self.type=ReorderOperation.TYPE if js: self.offset=js["offset"] def json(self): return { "type" : ReorderOperation.TYPE, "offset" : self.offset } @staticmethod def new(offset): tmp = ReorderOperation(None) tmp.offset=offset return tmp def __str__(self): return "Reorder(offset %d)" % self.offset class TranslateOperation(Operation): RELATIVE="RELATIVE" FIXED="FIXED" UNCHANGED="UNCHANGED" TYPE="TRANSLATE" def __init__(self, js): super().__init__(js) self.type=TranslateOperation.TYPE self.channelmode=TranslateOperation.RELATIVE self.keymode=TranslateOperation.RELATIVE self.velocitymode=TranslateOperation.RELATIVE self.channel=0 self.key=0 self.velocity=0 if js: self.channelmode=js["modes"][0] self.keymode=js["modes"][1] self.velocitymode=js["modes"][2] self.channel=js["values"][0] self.key=js["values"][1] self.velocity=js["values"][2] def __str__(self): ch = ("=" if self.channelmode=="FIXED" else ("+" if self.channel>=0 else "")) + str(self.channel) key = ("=" if self.keymode=="FIXED" else ("+" if self.key>=0 else "")) + str(self.key) vel = ("=" if self.velocitymode=="FIXED" else ("+" if self.velocity>=0 else "")) + str(self.velocity) return "Translate(channel %s, key %s, velocity %s)" % (ch, key, vel) def json(self): return { "type" : TranslateOperation.TYPE, "values" : [self.channel, self.key, self.velocity], "modes" : [self.channelmode, self.keymode, self.velocitymode] } @staticmethod def new(values=[0,0,0], modes=[False,False,False]): _modes=["FIXED" if modes[0] else "RELATIVE","FIXED" if modes[1] else "RELATIVE", "FIXED" if modes[2] else "RELATIVE"] return TranslateOperation({ "values" : values, "modes": _modes}) class RangeOperation(Operation): TYPE="RANGE" def __init__(self, js): super().__init__(js) self.type=RangeOperation.TYPE self.range=[] self.key=0 self.length=12 if js: self.range=js["range"] self.key=js["key"] self.length=js["length"] def json(self): return { "type" : RangeOperation.TYPE, "range" : self.range, "key" : self.key, "length" : self.length } def __str__(self): return "RANGE(range %s, key %d, len %d)" % (self.range, self.key, self.length) @staticmethod def new(range, key, length=12): tmp = RangeOperation(None) tmp.length=length tmp.range=range tmp.key=key return tmp CLASSES={ TranslateOperation.TYPE : TranslateOperation, DropOperation.TYPE : DropOperation, ReorderOperation.TYPE : ReorderOperation, RangeOperation.TYPE : RangeOperation } class Selection: def __init__(self, pad, js=None): self.pad=pad self.operations=[] self.locked=[] self.init=InputActionList([]) self.inputs=[] if js: for op in js["operations"]: self.operations.append(Operation.parse(op)) self.init=InputActionList(js["init"]) self.locked=[] for k in js["locked"]: self.locked.append(k[0]+k[1]*pad.width) def add_to_sel(self, i, j=0): if j>=0: i+=j*self.pad.width if not i in self.inputs: self.inputs.append(i) def remove_from_sel(self, i,j=-1): if j>=0: i+=j*self.pad.width if not i in self.inputs: return out=[] for k in self.inputs: if i!=k: out.append(k) self.inputs=out def json(self): ops = [] for op in self.operations: ops.append(op.json()) lock=[] for i in self.locked: lock.append([i%self.pad.width, math.floor(i/self.pad.width)]) return { "operations" : ops, "init" : self.init.json(), "locked" : lock } class PadConfiguration(Pad): def __init__(self, js, pad=None): self.pad=(js["pad"] if js else pad) super().__init__(PadManager.read_pad(self.pad)) self.conf_name="" self.description="" self.selections={} if js: self.conf_name = js["name"] self.description=js["description"] for k in js["selections"]: self.selections[k]=Selection(self, js["selections"][k]) for i in range(len(js["matrix"])): sel = self.selections[js["matrix"][i]] if js["matrix"][i] else None if sel: sel.inputs.append(i) def find_selection_of(self, x, y=-1): if y>=0: x+=y*self.width for sel in self.selections: if x in self.selections[sel].inputs: return sel return None def new_sel(self, name): sel = Selection(self) self.selections[name]=sel return sel def sel(self, name): return self.selections[name] def add_button_to(self, selname, i, j=-1): if j>=0: i+=j*self.pad.width for k in self.selections: self.selections[k].remove_from_sel(i) self.selections[selname].add_to_sel(i) def remove_button_selection(self, i, j=-1): if j>=0: i+=j*self.pad.width for k in self.selections: self.selections[k].remove_from_sel(i) def rename_selection(self, old, new): self.selections[new]=self.selections[old] del self.selections[old] def json(self): mat = [] for i in range(self.width*self.height): mat.append(self.find_selection_of(i)) sels = { } for k in self.selections: sels[k]=self.selections[k].json() return { "name" : self.conf_name, "description" : self.description, "pad" : self.pad, "selections" : sels, "matrix" : mat } @staticmethod def parse(file): with open(file) as f: return PadConfiguration(json.loads(f.read())) @staticmethod def new(pad): return PadConfiguration(None, pad)