pad.py 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  1. import math
  2. import json
  3. from padmanager import PadManager
  4. class InputAction(list):
  5. def __init__(self, js):
  6. super().__init__(js)
  7. def json(self):
  8. return self
  9. class InputActionList():
  10. def __init__(self, js):
  11. self.actions=[]
  12. if len(js)>0:
  13. if isinstance(js[0], str):
  14. self.actions.append(InputAction(js))
  15. else:
  16. for k in js:
  17. self.actions.append(k)
  18. def json(self):
  19. x=[]
  20. for k in self.actions:
  21. x.append(k)
  22. return x
  23. class InputDefinition:
  24. def __init__(self, js):
  25. self.type=js["type"]
  26. self.actions={}
  27. for k in js["actions"]:
  28. self.actions[k]=InputActionList(js["actions"][k])
  29. self.shape=js["shape"] if "shape" in js else ""
  30. def json(self):
  31. actions={}
  32. for k in self.actions:
  33. actions[k]=self.actions[k].json()
  34. return {
  35. "type" : self.type,
  36. "actions" : self.actions,
  37. "shape" : self.shape
  38. }
  39. class Pad:
  40. def __init__(self, js):
  41. self.name=js["name"]
  42. self.width=js["width"]
  43. self.height=js["height"]
  44. self.ports=js["ports"]
  45. self.inputs={}
  46. for k in js["inputs"]:
  47. self.inputs[k]=InputDefinition(js["inputs"][k])
  48. self.matrix=[]
  49. for i in range(self.width*self.height): self.matrix.append(None)
  50. for i in range(self.width*self.height):
  51. obj=js["matrix"][i]
  52. if obj:
  53. self.matrix[i]=self.inputs[obj["type"]]
  54. class Operation:
  55. def __init__(self, type, js=None):
  56. pass
  57. def json(self): raise NotImplementedError
  58. @staticmethod
  59. def parse(js):
  60. cl = CLASSES[js["type"]]
  61. return cl(js)
  62. class DropOperation(Operation):
  63. TYPE="DROP"
  64. def __init__(self, js):
  65. super().__init__(js)
  66. self.type=DropOperation.TYPE
  67. def json(self): return {"type" : DropOperation.TYPE}
  68. @staticmethod
  69. def new(): return DropOperation(None)
  70. def __str__(self):
  71. return "Drop()"
  72. class ReorderOperation(Operation):
  73. TYPE="REORDER"
  74. def __init__(self, js):
  75. super().__init__(js)
  76. self.type=ReorderOperation.TYPE
  77. if js:
  78. self.offset=js["offset"]
  79. def json(self):
  80. return {
  81. "type" : ReorderOperation.TYPE,
  82. "offset" : self.offset
  83. }
  84. @staticmethod
  85. def new(offset):
  86. tmp = ReorderOperation(None)
  87. tmp.offset=offset
  88. return tmp
  89. def __str__(self):
  90. return "Reorder(offset %d)" % self.offset
  91. class TranslateOperation(Operation):
  92. RELATIVE="RELATIVE"
  93. FIXED="FIXED"
  94. UNCHANGED="UNCHANGED"
  95. TYPE="TRANSLATE"
  96. def __init__(self, js):
  97. super().__init__(js)
  98. self.type=TranslateOperation.TYPE
  99. self.channelmode=TranslateOperation.RELATIVE
  100. self.keymode=TranslateOperation.RELATIVE
  101. self.velocitymode=TranslateOperation.RELATIVE
  102. self.channel=0
  103. self.key=0
  104. self.velocity=0
  105. if js:
  106. self.channelmode=js["modes"][0]
  107. self.keymode=js["modes"][1]
  108. self.velocitymode=js["modes"][2]
  109. self.channel=js["values"][0]
  110. self.key=js["values"][1]
  111. self.velocity=js["values"][2]
  112. def __str__(self):
  113. ch = ("=" if self.channelmode=="FIXED" else ("+" if self.channel>=0 else "")) + str(self.channel)
  114. key = ("=" if self.keymode=="FIXED" else ("+" if self.key>=0 else "")) + str(self.key)
  115. vel = ("=" if self.velocitymode=="FIXED" else ("+" if self.velocity>=0 else "")) + str(self.velocity)
  116. return "Translate(channel %s, key %s, velocity %s)" % (ch, key, vel)
  117. def json(self):
  118. return {
  119. "type" : TranslateOperation.TYPE,
  120. "values" : [self.channel, self.key, self.velocity],
  121. "modes" : [self.channelmode, self.keymode, self.velocitymode]
  122. }
  123. @staticmethod
  124. def new(values=[0,0,0], modes=[False,False,False]):
  125. _modes=["FIXED" if modes[0] else "RELATIVE","FIXED" if modes[1] else "RELATIVE",
  126. "FIXED" if modes[2] else "RELATIVE"]
  127. return TranslateOperation({ "values" : values, "modes": _modes})
  128. class RangeOperation(Operation):
  129. TYPE="RANGE"
  130. def __init__(self, js):
  131. super().__init__(js)
  132. self.type=RangeOperation.TYPE
  133. self.range=[]
  134. self.key=0
  135. self.length=12
  136. if js:
  137. self.range=js["range"]
  138. self.key=js["key"]
  139. self.length=js["length"]
  140. def json(self):
  141. return {
  142. "type" : RangeOperation.TYPE,
  143. "range" : self.range,
  144. "key" : self.key,
  145. "length" : self.length
  146. }
  147. def __str__(self):
  148. return "RANGE(range %s, key %d, len %d)" % (self.range, self.key, self.length)
  149. @staticmethod
  150. def new(range, key, length=12):
  151. tmp = RangeOperation(None)
  152. tmp.length=length
  153. tmp.range=range
  154. tmp.key=key
  155. return tmp
  156. CLASSES={
  157. TranslateOperation.TYPE : TranslateOperation,
  158. DropOperation.TYPE : DropOperation,
  159. ReorderOperation.TYPE : ReorderOperation,
  160. RangeOperation.TYPE : RangeOperation
  161. }
  162. class Selection:
  163. def __init__(self, pad, js=None):
  164. self.pad=pad
  165. self.operations=[]
  166. self.locked=[]
  167. self.init=InputActionList([])
  168. self.inputs=[]
  169. if js:
  170. for op in js["operations"]:
  171. self.operations.append(Operation.parse(op))
  172. self.init=InputActionList(js["init"])
  173. self.locked=[]
  174. for k in js["locked"]:
  175. self.locked.append(k[0]+k[1]*pad.width)
  176. def add_to_sel(self, i, j=0):
  177. if j>=0: i+=j*self.pad.width
  178. if not i in self.inputs:
  179. self.inputs.append(i)
  180. def remove_from_sel(self, i,j=-1):
  181. if j>=0: i+=j*self.pad.width
  182. if not i in self.inputs: return
  183. out=[]
  184. for k in self.inputs:
  185. if i!=k:
  186. out.append(k)
  187. self.inputs=out
  188. def json(self):
  189. ops = []
  190. for op in self.operations:
  191. ops.append(op.json())
  192. lock=[]
  193. for i in self.locked:
  194. lock.append([i%self.pad.width, math.floor(i/self.pad.width)])
  195. return {
  196. "operations" : ops,
  197. "init" : self.init.json(),
  198. "locked" : lock
  199. }
  200. class PadConfiguration(Pad):
  201. def __init__(self, js, pad=None):
  202. self.pad=(js["pad"] if js else pad)
  203. super().__init__(PadManager.read_pad(self.pad))
  204. self.conf_name=""
  205. self.description=""
  206. self.selections={}
  207. if js:
  208. self.conf_name = js["name"]
  209. self.description=js["description"]
  210. for k in js["selections"]:
  211. self.selections[k]=Selection(self, js["selections"][k])
  212. for i in range(len(js["matrix"])):
  213. sel = self.selections[js["matrix"][i]] if js["matrix"][i] else None
  214. if sel: sel.inputs.append(i)
  215. def find_selection_of(self, x, y=-1):
  216. if y>=0: x+=y*self.width
  217. for sel in self.selections:
  218. if x in self.selections[sel].inputs: return sel
  219. return None
  220. def new_sel(self, name):
  221. sel = Selection(self)
  222. self.selections[name]=sel
  223. return sel
  224. def sel(self, name):
  225. return self.selections[name]
  226. def add_button_to(self, selname, i, j=-1):
  227. if j>=0: i+=j*self.pad.width
  228. for k in self.selections:
  229. self.selections[k].remove_from_sel(i)
  230. self.selections[selname].add_to_sel(i)
  231. def remove_button_selection(self, i, j=-1):
  232. if j>=0: i+=j*self.pad.width
  233. for k in self.selections:
  234. self.selections[k].remove_from_sel(i)
  235. def rename_selection(self, old, new):
  236. self.selections[new]=self.selections[old]
  237. del self.selections[old]
  238. def json(self):
  239. mat = []
  240. for i in range(self.width*self.height):
  241. mat.append(self.find_selection_of(i))
  242. sels = {
  243. }
  244. for k in self.selections:
  245. sels[k]=self.selections[k].json()
  246. return {
  247. "name" : self.conf_name,
  248. "description" : self.description,
  249. "pad" : self.pad,
  250. "selections" : sels,
  251. "matrix" : mat
  252. }
  253. @staticmethod
  254. def parse(file):
  255. with open(file) as f:
  256. return PadConfiguration(json.loads(f.read()))
  257. @staticmethod
  258. def new(pad):
  259. return PadConfiguration(None, pad)