Collection of tools useful for audio production
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

297 lines
8.6KB

  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3. # Helper functions for extra caitlib functionality
  4. # Copyright (C) 2012 Filipe Coelho <falktx@falktx.com>
  5. #
  6. # This program is free software; you can redistribute it and/or modify
  7. # it under the terms of the GNU General Public License as published by
  8. # the Free Software Foundation; either version 2 of the License, or
  9. # any later version.
  10. #
  11. # This program is distributed in the hope that it will be useful,
  12. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. # GNU General Public License for more details.
  15. #
  16. # For a full copy of the GNU General Public License see the COPYING file
  17. import caitlib
  18. # ------------------------------------------------------------------------------
  19. # Instances
  20. # Caitlib instance
  21. class CailibInstance(object):
  22. def __init__(self, instanceName):
  23. object.__init__(self)
  24. try:
  25. self.m_lib = caitlib.init(instanceName)
  26. except:
  27. self.m_lib = None
  28. def isOk(self):
  29. return bool(self.m_lib)
  30. def close(self):
  31. caitlib.close(self.m_lib)
  32. self.m_lib = None
  33. # ---------------------------------
  34. def createPort(self, portName):
  35. return CailibPort(self.m_lib, portName)
  36. # ---------------------------------
  37. def wantEvents(self, yesNo):
  38. caitlib.want_events(self.m_lib, yesNo)
  39. def getEvent(self):
  40. return caitlib.get_event(self.m_lib)
  41. # Caitlib port
  42. class CailibPort(object):
  43. def __init__(self, instance, portName):
  44. object.__init__(self)
  45. self.m_lib = instance
  46. self.m_port = caitlib.create_port(self.m_lib, portName)
  47. def isOk(self):
  48. return bool(self.m_port >= 0)
  49. def destroy(self):
  50. caitlib.destroy_port(self.m_lib, self.m_port)
  51. self.m_port = -1
  52. # ---------------------------------
  53. def addControl(self, time, channel, controller, value):
  54. return ControlEvent(self, time, channel, controller, value)
  55. def addNote(self, time, channel, pitch, velocity, duration):
  56. return NoteEvent(self, time, channel, pitch, velocity, duration)
  57. def addChannelPressure(self, time, channel, value):
  58. return ChannelPressureEvent(self, time, channel, value)
  59. def addProgram(self, time, channel, bank, program):
  60. return ProgramEvent(self, time, channel, bank, program)
  61. def addPitchWheel(self, time, channel, value):
  62. return PitchWheelEvent(self, time, channel, value)
  63. # ------------------------------------------------------------------------------
  64. # Events
  65. # Abstract event
  66. class AbstractEvent(object):
  67. def __init__(self, port, time, channel):
  68. object.__init__(self)
  69. if 0 < channel > 15:
  70. print("AbstractEvent(%i, %i) - invalid channel", time, channel)
  71. channel = 0
  72. if time < 0:
  73. print("AbstractEvent(%i, %i) - invalid time", time, channel)
  74. time = 0
  75. # Channel, 0 - 15
  76. self.m_channel = channel
  77. # Time in which the event starts, in ticks
  78. self.m_time = time
  79. # Store port instance for later
  80. self.m_port = port
  81. def channel(self):
  82. return self.m_channel
  83. def time(self):
  84. return self.m_time
  85. def getRawMidiData(self):
  86. return ()
  87. # Control event
  88. class ControlEvent(AbstractEvent):
  89. def __init__(self, port, time, channel, controller, value):
  90. AbstractEvent.__init__(self, port, time, channel)
  91. if 1 < controller > 127:
  92. print("ControlEvent(%i, %i) - invalid controller", controller, value)
  93. controller = 0
  94. if 0 < value > 127:
  95. print("ControlEvent(%i, %i) - invalid value", controller, value)
  96. value = 0
  97. # Controller
  98. self.m_controller = controller
  99. # Value
  100. self.m_value = value
  101. # Put event in caitlib
  102. caitlib.put_control(self.m_port.m_lib, self.m_port.m_port, self.m_time, self.m_channel, self.m_controller, self.m_value)
  103. def controller(self):
  104. return self.m_controller
  105. def value(self):
  106. return self.m_value
  107. def getRawMidiData(self):
  108. event = { self.m_time:
  109. (caitlib.MIDI_EVENT_TYPE_CONTROL + self.m_channel, self.m_controller, self.m_value)
  110. }
  111. return (event,)
  112. # Note event
  113. class NoteEvent(AbstractEvent):
  114. def __init__(self, port, time, channel, pitch, velocity, duration):
  115. AbstractEvent.__init__(self, port, time, channel)
  116. if duration < 1:
  117. print("NoteEvent(%i, %i, %i) - invalid duration", pitch, velocity, duration)
  118. duration = 1
  119. if 0 < pitch > 127:
  120. print("NoteEvent(%i, %i, %i) - invalid pitch", pitch, velocity, duration)
  121. pitch = 0
  122. if 0 < velocity > 127:
  123. print("NoteEvent(%i, %i, %i) - invalid velocity", pitch, velocity, duration)
  124. velocity = 0
  125. # Duration of note, in ticks
  126. self.m_duration = duration
  127. # Pitch
  128. self.m_pitch = pitch
  129. # Velocity
  130. self.m_velocity = velocity
  131. # Put event in caitlib
  132. caitlib.put_note_on(self.m_port.m_lib, self.m_port.m_port, self.m_time, self.m_channel, self.m_pitch, self.m_velocity)
  133. caitlib.put_note_off(self.m_port.m_lib, self.m_port.m_port, self.m_time+self.m_duration, self.m_channel, self.m_pitch, self.m_velocity)
  134. def duration(self):
  135. return self.m_duration
  136. def pitch(self):
  137. return self.m_pitch
  138. def velocity(self):
  139. return self.m_velocity
  140. def getRawMidiData(self):
  141. noteOn = { self.m_time:
  142. (caitlib.MIDI_EVENT_TYPE_NOTE_ON + self.m_channel, self.m_pitch, self.m_velocity)
  143. }
  144. noteOff = { self.m_time+self.m_duration:
  145. (caitlib.MIDI_EVENT_TYPE_NOTE_OFF + self.m_channel, self.m_pitch, self.m_velocity)
  146. }
  147. return (noteOn, noteOff)
  148. # Channel pressure event
  149. class ChannelPressureEvent(AbstractEvent):
  150. def __init__(self, port, time, channel, value):
  151. AbstractEvent.__init__(self, port, time, channel)
  152. if 0 < value > 127:
  153. print("ChannelPressureEvent(%i) - invalid value", value)
  154. value = 100
  155. # Value
  156. self.m_value = value
  157. # Put event in caitlib
  158. caitlib.put_channel_pressure(self.m_port.m_lib, self.m_port.m_port, self.m_time, self.m_channel, self.m_value)
  159. def value(self):
  160. return self.m_value
  161. def getRawMidiData(self):
  162. event = { self.m_time:
  163. (caitlib.MIDI_EVENT_TYPE_CHANNEL_PRESSURE + self.m_channel, self.m_value)
  164. }
  165. return (event,)
  166. # Program event
  167. class ProgramEvent(AbstractEvent):
  168. def __init__(self, port, time, channel, bank, program):
  169. AbstractEvent.__init__(self, port, time, channel)
  170. if 0 < bank > 127:
  171. print("ProgramEvent(%i, %i) - invalid bank", bank, program)
  172. bank = 0
  173. if 0 < program > 127:
  174. print("ProgramEvent(%i, %i) - invalid program", bank, program)
  175. program = 0
  176. # Bank
  177. self.m_bank = bank
  178. # Program
  179. self.m_program = program
  180. # Put event in caitlib
  181. caitlib.put_control(self.m_port.m_lib, self.m_port.m_port, self.m_time, self.m_channel, 0, self.m_bank)
  182. caitlib.put_program(self.m_port.m_lib, self.m_port.m_port, self.m_time, self.m_channel, self.m_program)
  183. def bank(self):
  184. return self.m_bank
  185. def program(self):
  186. return self.m_program
  187. def getRawMidiData(self):
  188. bank = { self.m_time:
  189. (caitlib.MIDI_EVENT_TYPE_CONTROL + self.m_channel, 0x00, self.m_bank)
  190. }
  191. program = { self.m_time:
  192. (caitlib.MIDI_EVENT_TYPE_PROGRAM + self.m_channel, self.m_program)
  193. }
  194. return (bank, program)
  195. # PitchWheel event
  196. class PitchWheelEvent(AbstractEvent):
  197. def __init__(self, port, time, channel, value):
  198. AbstractEvent.__init__(self, port, time, channel)
  199. if -8192 < value > 8192:
  200. print("PitchWheelEvent(%i) - invalid value", value)
  201. value = 0
  202. # Value
  203. self.m_value = value
  204. # Put event in caitlib
  205. caitlib.put_pitchwheel(self.m_port.m_lib, self.m_port.m_port, self.m_time, self.m_channel, self.m_value)
  206. def value(self):
  207. return self.m_value
  208. def getRawMidiData(self):
  209. value = self.m_value + 8192;
  210. lsb = value & 0x7F
  211. msb = value >> 7
  212. event = { self.m_time:
  213. (caitlib.MIDI_EVENT_TYPE_PITCH_WHEEL + self.m_channel, lsb, msb)
  214. }
  215. return (event,)
  216. # ------------------------------------------------------------------------------
  217. # Data Sets
  218. class Part(object):
  219. def __init__(self):
  220. object.__init__(self)