midieventtrigger.py 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. #!/usr/bin/python
  2. import copy
  3. from .midimessage import MidiType
  4. from .utils import *
  5. class MidiEventTrigger:
  6. NOTE=1
  7. CONTROL=2
  8. PROGRAM=4
  9. FILTER_ALL_KEY=-1
  10. def __init__(self, param):
  11. if param==None: self._initNone()
  12. elif isinstance(param, (tuple, list)): self._initTuple(param)
  13. elif isinstance(param, int): self._initTuple([param])
  14. elif isinstance(param, MidiEventTrigger): self._initCopy(param)
  15. def _initNone(self):
  16. self._init()
  17. """
  18. () -> déclenchement pour toutes les evenemnts parmis NOTE, CONTROL et PROGRAM
  19. (TYPE)
  20. (TYPE, CHANNEL, NOTE)
  21. (TYPE, CHANNEL, NOTE, FORWARD)
  22. (TYPE, CHANNEL, NOTE, FORWARD, CALLBACK [, DATA])
  23. TYPE: flags parmis NOTE, CONTROL, PROGRAM (qui sera une condition necessaire au déclenchement)
  24. CHANNEL: le canal pour le déclenchement
  25. none ou vide: declenchement pour toutes les valeurs
  26. int: declenchement pour une valeur
  27. array: declenchement pour toutes les valeurs de la liste
  28. tuple: declenchement pour l'interval (x,y) avec x ET y inclus
  29. NOTE: la clé de la Note du Program ou Control pour le déclenchement
  30. none ou vide: declenchement pour toutes les valeurs
  31. int: declenchement pour une valeur
  32. array: declenchement pour toutes les valeurs de la liste
  33. tuple: declenchement pour l'interval (x,y) avec x ET y inclus
  34. FORWARD: Uen fois l'élément traité doit il etre réinjecter en canal de sortie ?
  35. True ou vide: Oui
  36. None ou False: Non
  37. CALLBACK et DATA:
  38. callback appelé en cas de céclenchement de la forem fct(msg, data)
  39. """
  40. def _initTuple(self, t):
  41. self._init(*t)
  42. def _initCopy(self, t):
  43. _init(t.type, copy.copy(t.channel), copy.copy(t.key), t.forward)
  44. def _init(self, t=NOTE|CONTROL|PROGRAM, ch=None, k=None, f=True, cb=None, data=None ):
  45. self.channel=self.FILTER_ALL_KEY
  46. self.key=self.FILTER_ALL_KEY
  47. self.forward=True
  48. self.type=t
  49. if isinstance(ch, list):
  50. self.channel=ch
  51. elif isinstance(ch, tuple):
  52. self.channel=[]
  53. for i in range(ch[0], ch[1]+1):
  54. self.channel.append(i)
  55. if isinstance(k, list):
  56. self.key=k
  57. elif isinstance(k, tuple):
  58. self.key=[]
  59. for i in range(k[0], k[1]+1):
  60. self.key.append(i)
  61. self.forward=f
  62. self.callback=cb
  63. self.callbackData=data
  64. def trigger(self, msg):
  65. if self.callback:
  66. self.callback(msg, self.callbackData)
  67. def filter(self, _msg, out):
  68. msg=_msg[1]
  69. delta=_msg[0]
  70. t=msg.getType()
  71. if t!=MidiType.NOTE_ON and t!=MidiType.NOTE_OFF and \
  72. t!=MidiType.PROGRAM_CHANGE and t!=MidiType.CONTROL_CHANGE: return False
  73. #test du type
  74. lt=[]
  75. if self.type & self.NOTE: lt+=[MidiType.NOTE_ON, MidiType.NOTE_OFF]
  76. if self.type & self.CONTROL: lt+=[MidiType.CONTROL_CHANGE]
  77. if self.type & self.PROGRAM: lt+=[MidiType.PROGRAM_CHANGE]
  78. ok=False
  79. for tt in lt:
  80. if tt==t:
  81. ok=True
  82. break
  83. if not ok: return False
  84. if self.key!=None and self.key!=-1 and not (msg.key in self.key): return False
  85. if self.channel!=None and self.channel!=-1 and not (msg.key in self.channel): return False
  86. if out!=None and self.forward: out.send(msg)
  87. print(msg)
  88. self.trigger(msg)
  89. return True
  90. class MidiMultiTrigger:
  91. """
  92. param={
  93. id_1 : PARAM_TO_MIDI_EVENT_TRIGGER,
  94. id_2 : PARAM_TO_MIDI_EVENT_TRIGGER,
  95. ...
  96. id_n : PARAM_TO_MIDI_EVENT_TRIGGER,
  97. }
  98. """
  99. def __init__(self, param={}):
  100. if not isinstance(param, dict): raise Exception("MidiMultiTrigger expects an dict argument")
  101. self.data={}
  102. for i in param.keys():
  103. self.addTrigger(i, param[i])
  104. def addTrigger(self, name, param):
  105. self.data[name]=MidiEventTrigger(param)
  106. """
  107. names: None ou une liste des id a tester
  108. renvoie une liste des declenchements
  109. """
  110. def filter(self, msg, out, names=None):
  111. ret=[]
  112. toTest=self.data.keys()
  113. if names!=None: toTest=names
  114. for i in toTest:
  115. if self.data[i].filter(msg, out): ret.append(i)
  116. return ret